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

Revision 692, 55.1 KB checked in by mattausch, 19 years ago (diff)

adding ogre 1.2 and dependencies

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#include <xsi_edge.h>
40#include <xsi_vector3.h>
41#include <xsi_matrix4.h>
42#include <xsi_mixer.h>
43#include <xsi_clip.h>
44#include <xsi_timecontrol.h>
45#include <xsi_actionsource.h>
46#include <xsi_fcurve.h>
47#include <xsi_fcurvekey.h>
48
49#include "OgreException.h"
50#include "OgreXSIHelper.h"
51#include "OgreLogManager.h"
52#include "OgreMeshManager.h"
53#include "OgreMesh.h"
54#include "OgreSubMesh.h"
55#include "OgreMeshManager.h"
56#include "OgreMeshSerializer.h"
57#include "OgreHardwareBufferManager.h"
58#include "OgreVertexBoneAssignment.h"
59#include "OgrePose.h"
60#include "OgreAnimation.h"
61#include "OgreAnimationTrack.h"
62
63using namespace XSI;
64
65
66namespace Ogre {
67    //-----------------------------------------------------------------------
68    XsiMeshExporter::UniqueVertex::UniqueVertex()
69        : position(Vector3::ZERO), normal(Vector3::ZERO), colour(0), nextIndex(0)
70    {
71        for (int i = 0; i < OGRE_MAX_TEXTURE_COORD_SETS; ++i)
72            uv[i] = Vector3::ZERO;
73    }
74    //-----------------------------------------------------------------------
75    bool XsiMeshExporter::UniqueVertex::operator==(const UniqueVertex& rhs) const
76    {
77        bool ret = position == rhs.position &&
78            normal == rhs.normal &&
79            colour == rhs.colour;
80        if (!ret) return ret;
81
82        for (int i = 0; i < OGRE_MAX_TEXTURE_COORD_SETS && ret; ++i)
83        {
84            ret = ret && (uv[i] == rhs.uv[i]);
85        }
86
87        return ret;
88       
89
90    }
91    //-----------------------------------------------------------------------
92    //-----------------------------------------------------------------------
93    XsiMeshExporter::XsiMeshExporter()
94    {
95    }
96    //-----------------------------------------------------------------------
97    XsiMeshExporter::~XsiMeshExporter()
98    {
99                /// Tidy up
100                cleanupDeformerMap();
101                cleanupMaterialMap();
102    }
103    //-----------------------------------------------------------------------
104        DeformerMap& XsiMeshExporter::exportMesh(const String& fileName,
105                bool mergeSubMeshes, bool exportChildren,
106                bool edgeLists, bool tangents, bool vertexAnimation,
107                AnimationList& animList, Real fps, const String& materialPrefix,
108                LodData* lod, const String& skeletonName)
109    {
110
111                LogOgreAndXSI(L"** Begin OGRE Mesh Export **");
112        // Derive the scene root
113        X3DObject sceneRoot(mXsiApp.GetActiveSceneRoot());
114
115        // Construct mesh
116        MeshPtr pMesh = MeshManager::getSingleton().createManual("XSIExport",
117                        ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
118
119                mMaterialPrefix = materialPrefix;
120
121                cleanupDeformerMap();
122                cleanupMaterialMap();
123                mShapeKeyMapping.clear();
124
125                // Find all PolygonMesh objects
126                buildPolygonMeshList(exportChildren);
127                // progress report
128                ProgressManager::getSingleton().progress();
129
130                // notify of skeleton beforehand
131                if (!skeletonName.empty())
132                {
133                        pMesh->setSkeletonName(skeletonName);
134                }
135
136                // write the data into a mesh
137                buildMesh(pMesh.getPointer(), mergeSubMeshes, !skeletonName.empty(),
138                        vertexAnimation, animList, fps);
139
140                // progress report
141                ProgressManager::getSingleton().progress();
142
143                if (lod)
144                {
145                        pMesh->generateLodLevels(lod->distances, lod->quota, lod->reductionValue);
146                        // progress report
147                        ProgressManager::getSingleton().progress();
148                }
149
150        if(edgeLists)
151        {
152            LogOgreAndXSI(L"Calculating edge lists");
153            pMesh->buildEdgeList();
154                        // progress report
155                        ProgressManager::getSingleton().progress();
156        }
157
158        if(tangents)
159        {
160            LogOgreAndXSI(L"Calculating tangents");
161            unsigned short src, dest;
162            if (pMesh->suggestTangentVectorBuildParams(src, dest))
163            {
164                pMesh->buildTangentVectors(src, dest);
165            }
166            else
167            {
168                LogOgreAndXSI(L"Could not derive tangents parameters");
169            }
170                        // progress report
171                        ProgressManager::getSingleton().progress();
172
173        }
174
175        MeshSerializer serializer;
176        serializer.exportMesh(pMesh.getPointer(), fileName);
177
178                // progress report
179                ProgressManager::getSingleton().progress();
180
181                cleanupPolygonMeshList();
182
183                LogOgreAndXSI(L"** OGRE Mesh Export Complete **");
184
185                return mXsiDeformerMap;
186    }
187        //-----------------------------------------------------------------------
188        MaterialMap& XsiMeshExporter::getMaterials(void)
189        {
190                return mXsiMaterialMap;
191        }
192        //-----------------------------------------------------------------------
193        TextureProjectionMap& XsiMeshExporter::getTextureProjectionMap(void)
194        {
195                return mTextureProjectionMap;
196        }
197        //-----------------------------------------------------------------------
198        void XsiMeshExporter::buildMesh(Mesh* pMesh, bool mergeSubmeshes,
199                bool lookForBoneAssignments, bool vertexAnimation, AnimationList& animList,
200                Real fps)
201        {
202                /* Iterate over the list of polygon meshes that we've already located.
203                        For each one:
204                                If we're not merging submeshes, bake any protosubmeshes built
205                                  into the mesh and clear the protosubmesh list
206                            Scan the clusters for 'poly' clusters (which can contain material
207                                  discrepancies). Any that use a different material should be
208                                  noted in the polycluster list
209                            Build ProtoSubMeshes by iterating over the triangles in the mesh,
210                                  building the list of UniqueVertices against the material as we
211                                  go. We check each triangle to see if the polygon index is in
212                                  the list of polyclusters & if so it goes into the other lists
213                   
214                        Finally, we bake any remaining protosubmeshes into submeshes.
215                */
216                // Calculate the number of progress updates each mesh must raise
217                float progPerMesh = (float)OGRE_XSI_NUM_MESH_STEPS / (float)(mXsiPolygonMeshList.size());
218                float currProg = 0.0f;
219                for (PolygonMeshList::iterator pm = mXsiPolygonMeshList.begin();
220                        pm != mXsiPolygonMeshList.end(); ++pm)
221                {
222                        currProg += progPerMesh;
223                        unsigned short progUpdates = (unsigned short)currProg;
224                        currProg -= progUpdates;
225                        // build contents of this polymesh into ProtoSubMesh(es)
226                        processPolygonMesh(pMesh, *pm, lookForBoneAssignments, progUpdates);
227
228                        if (!mergeSubmeshes)
229                        {
230                                // export out at the end of every PolygonMesh
231                                exportProtoSubMeshes(pMesh);
232                        }
233                }
234                if (mergeSubmeshes)
235                {
236                        // export out the combined result
237                        exportProtoSubMeshes(pMesh);
238                }
239
240                if (vertexAnimation)
241                {
242                        exportAnimations(pMesh, animList, fps);
243                }
244        }
245        //-----------------------------------------------------------------------
246        XsiMeshExporter::ProtoSubMesh* XsiMeshExporter::createOrRetrieveProtoSubMesh(
247                const String& materialName, const String& name,
248                TextureCoordDimensionList& texCoordDims, bool hasVertexColours)
249        {
250                bool createNew = false;
251                ProtoSubMesh* ret = 0;
252               
253                ProtoSubMeshList::iterator pi = mProtoSubmeshList.find(materialName);
254                if (pi == mProtoSubmeshList.end())
255                {
256                        createNew = true;
257                }
258                else
259                {
260                        // Check format is compatible
261                        bool compat = true;
262                        if (pi->second->textureCoordDimensions.size() != texCoordDims.size())
263                        {
264                                compat = false;
265                        }
266                        if (pi->second->hasVertexColours != hasVertexColours)
267                        {
268                                compat = false;
269                        }
270                        std::vector<ushort>::iterator t = texCoordDims.begin();
271                        std::vector<ushort>::iterator u = pi->second->textureCoordDimensions.begin();
272                        for (;t != texCoordDims.end(); ++t,++u)
273                        {
274                                if (*t != *u)
275                                {
276                                        compat = false;
277                                        break;
278                                }
279                        }
280                       
281                        if (compat)
282                        {
283                                ret = pi->second;
284                        }
285                        else
286                        {
287                                // Can't merge these - create new
288                                createNew = true;
289                        }
290                }
291
292                if (createNew)
293                {
294                        ret = new ProtoSubMesh();
295                        mProtoSubmeshList[materialName] = ret;
296                        ret->materialName = materialName;
297                        ret->name = name;
298                        ret->textureCoordDimensions = texCoordDims;
299                        ret->hasVertexColours = hasVertexColours;
300                }
301
302                return ret;
303               
304        }
305        //-----------------------------------------------------------------------
306        void XsiMeshExporter::processPolygonMesh(Mesh* pMesh, PolygonMeshEntry* xsiMesh,
307                bool lookForBoneAssignments, unsigned short progressUpdates)
308        {
309                // Pre-process the mesh
310                if (!preprocessPolygonMesh(xsiMesh))
311                {
312                        while(progressUpdates--)
313                                ProgressManager::getSingleton().progress();
314
315                        return;
316                }
317               
318        // Retrieve all the XSI relevant summary info
319        CPointRefArray pointArray(xsiMesh->mesh.GetPoints());
320        MATH::CVector3Array srcPosArray = pointArray.GetPositionArray();
321        CPolygonNodeRefArray nodeArray(xsiMesh->mesh.GetNodes());
322        MATH::CVector3Array srcNormArray = nodeArray.GetNormalArray();
323        CTriangleRefArray triArray = xsiMesh->mesh.GetTriangles();
324
325                StringUtil::StrStreamType msg;
326                msg << "-- " << XSItoOgre(xsiMesh->obj.GetName()) << " --" << std::endl;
327                msg << "Points: " << pointArray.GetCount() << std::endl;
328                msg << "Triangles: " << triArray.GetCount() << std::endl;
329                msg << "Normals: " << srcNormArray.GetCount() << std::endl;
330                msg << "Num UVs: " << mCurrentTextureCoordDimensions.size() << std::endl;
331                String str = msg.str();
332                LogOgreAndXSI(str);
333
334                if (mCurrentTextureCoordDimensions.size() > OGRE_MAX_TEXTURE_COORD_SETS)
335                {
336                        // too many texture coordinates!
337                        StringUtil::StrStreamType str;
338                        str << "PolygonMesh '" << XSItoOgre(xsiMesh->mesh.GetName())
339                                << "' has too many texture coordinate sets ("
340                                << mCurrentTextureCoordDimensions.size()
341                                << "); the limit is " << OGRE_MAX_TEXTURE_COORD_SETS;
342
343                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, str.str(),
344                                "XsiMeshExporter::processPolygonMesh");
345
346                }
347               
348                // Save transforms
349                MATH::CTransformation xsiTransform = xsiMesh->obj.GetKinematics().GetGlobal().GetTransform();
350                MATH::CTransformation rotTrans;
351                rotTrans.SetRotation(xsiTransform.GetRotation());
352                // Bounds calculation
353        Real squaredRadius = 0.0f;
354        Vector3 min, max;
355        bool first = true;
356                CPolygonFaceRefArray polys(xsiMesh->mesh.GetPolygons());
357        UniqueVertex vertex;
358
359
360                float progPerTri = (float)progressUpdates / triArray.GetCount();
361                float prog = 0.0f;
362                // Iterate through all the triangles
363        // There will often be less positions than normals and UVs
364        // But TrianglePoint
365        for (long t = 0; t < triArray.GetCount(); ++t)
366        {
367            Triangle tri(triArray[t]);
368                        // derive sampler indices for triangle
369                        size_t samplerIndices[3];
370                        deriveSamplerIndices(tri, polys[tri.GetPolygonIndex()], samplerIndices);
371
372                        // Decide which ProtoSubMesh we're to add this to (assume main)
373                        // If we find this triangle relates to a polygon which is in
374                        // a cluster which has a different material, we change
375                        ProtoSubMesh* currentProto = mMainProtoMesh;
376                        PolygonToProtoSubMeshList::iterator polyi =
377                                mPolygonToProtoSubMeshList.find(tri.GetPolygonIndex());
378                        if (polyi != mPolygonToProtoSubMeshList.end())
379                        {
380                                currentProto = polyi->second;
381                        }
382                        // has this mesh been used in this proto before? if not set offset
383                        size_t positionIndexOffset;
384                        if (currentProto->lastMeshEntry == xsiMesh)
385                        {
386                                positionIndexOffset = currentProto->lastMeshIndexOffset;
387                        }
388                        else
389                        {
390                                // first time this has been used
391                                // since we assume we 100% process each polygon mesh before the next,
392                                // just use last pointer since faster in this section
393                                currentProto->lastMeshEntry = xsiMesh;
394                                positionIndexOffset = currentProto->indices.size();
395                                currentProto->lastMeshIndexOffset = positionIndexOffset;
396                                // Also have to store this for future reference
397                                currentProto->polygonMeshOffsetMap[xsiMesh] = positionIndexOffset;
398                        }
399                       
400            CTriangleVertexRefArray points = tri.GetPoints();
401            for (long p = 0; p < 3; ++p)
402            {
403                TriangleVertex point(points[p]);
404                long posIndex = point.GetIndex(); // unique position index
405                                // adjust index per offset, this makes position indices unique
406                                // per polymesh in teh same protosubmesh
407                                posIndex += positionIndexOffset;
408
409                                // Get position
410                                MATH::CVector3 xsipos = point.GetPosition();
411                                // Apply global SRT
412                                xsipos.MulByTransformationInPlace(xsiTransform);
413                vertex.position = XSItoOgre(xsipos);
414                                // Get normal
415                                MATH::CVector3 xsinorm = point.GetNormal();
416                                // Apply global rotation
417                                xsinorm *= rotTrans;
418                vertex.normal = XSItoOgre(xsinorm);
419
420                                for (size_t i = 0; i < mCurrentTextureCoordDimensions.size(); ++i)
421                                {
422                                        // sampler indices can correctly dereference to sampler-order
423                                        // uv sets we built earlier
424                                        vertex.uv[i] = (mCurrentSamplerSets[i])[samplerIndices[p]];
425                                }
426               
427                if (mCurrentHasVertexColours)
428                    vertex.colour = XSItoOgre(point.GetColor());
429
430                size_t index = createOrRetrieveUniqueVertex(
431                                                                        currentProto, posIndex, true, vertex);
432                currentProto->indices.push_back(index);
433
434                                // bounds
435                                if (first)
436                                {
437                                        squaredRadius = vertex.position.squaredLength();
438                                        min = max = vertex.position;
439                                        first = false;
440                                }
441                                else
442                                {
443                                        squaredRadius =
444                                                std::max(squaredRadius, vertex.position.squaredLength());
445                                        min.makeFloor(vertex.position);
446                                        max.makeCeil(vertex.position);
447                                }
448            }
449               
450                        // Progress
451                        prog += progPerTri;
452                        while (prog >= 1.0f)
453                        {
454                                ProgressManager::getSingleton().progress();
455                                prog -= 1.0f;
456                        }
457
458                }
459
460                // Merge bounds
461                AxisAlignedBox box;
462        box.setExtents(min, max);
463        box.merge(pMesh->getBounds());
464        pMesh->_setBounds(box);
465        pMesh->_setBoundingSphereRadius(
466                        std::max(
467                                pMesh->getBoundingSphereRadius(),
468                                Math::Sqrt(squaredRadius)));
469
470                // Deal with any bone assignments
471                if (lookForBoneAssignments)
472                {
473                        processBoneAssignments(pMesh, xsiMesh);
474                }
475
476                // process any shape keys
477                processShapeKeys(pMesh, xsiMesh);
478
479                // Post-process the mesh
480                postprocessPolygonMesh(xsiMesh);
481
482        }
483        //-----------------------------------------------------------------------
484        bool XsiMeshExporter::preprocessPolygonMesh(PolygonMeshEntry* xsiMesh)
485        {
486        // derive number of UVs
487        int numUVs = 0;
488        CRefArray clusterRefArray;
489        // Filter to 'sample' types
490        xsiMesh->mesh.GetClusters().Filter(
491                        siSampledPointCluster,CStringArray(),L"",clusterRefArray);
492
493        Cluster samplePointClusterUV;
494        CRefArray uvClusterPropertiesRefArray;
495                int i;
496       
497        for(i = 0; i < clusterRefArray.GetCount(); ++i)
498        {
499            Cluster cluster(clusterRefArray[i]);               
500            // Now filter all the 'uvspace' children
501            // there is one of these per UV set
502            if(cluster.GetProperties().Filter(
503                siClsUVSpaceTxtType, CStringArray(), L"",
504                uvClusterPropertiesRefArray) == CStatus::OK)
505            {
506                samplePointClusterUV = cluster;                 
507                break;
508            }
509        }
510
511        // Ok, we now have our array of UV sets
512        numUVs = uvClusterPropertiesRefArray.GetCount();
513                size_t numSamplerPoints = xsiMesh->mesh.GetNodes().GetCount();
514                // list of UVs stored in order of sampler points (use 3D coords by default)
515                mCurrentSamplerSets.reserve(numUVs);
516                mCurrentTextureCoordDimensions.reserve(numUVs);
517        for(i = 0; i < numUVs; ++i)
518        {
519                        // init sampler points
520                        Vector3* samplerUVs = new Vector3[numSamplerPoints];
521                        mCurrentSamplerSets.push_back(samplerUVs);
522
523                        // Detect the dimensions by figuring out if any are all 0
524                        bool hasU, hasV, hasW;
525                        hasU = hasV = hasW = false;
526
527                        // Pull out all the UV data for this set and reorder it based on
528                        // samples, we'll need this for reference later
529                        // get Elements from uvspace Property
530            ClusterProperty uvProp(uvClusterPropertiesRefArray[i]);
531                        CClusterPropertyElementArray uvElements = uvProp.GetElements();
532
533                        // Add this to an map from uv set name to index
534                        String textureProjectionName = XSItoOgre(uvProp.GetName());
535                        mTextureProjectionMap[textureProjectionName] = i;
536
537                        // Now, each Element here is actually a CDoubleArray of the u,v,w values
538                        // However it's not in order of samplers, we need to use the Array
539                        // linked to from the Elements collection under the cluster (not the
540                        // cluster property, confusing I know) to figure out what sampler
541                        // index it is, i.e.
542                        // samplerUVs[Array[j]] = Element[j]
543                        // In all casesmCurrentSamplerSets in XSI element properties are referenced back to
544                        // their original poly index via this array, ie all cluster properties
545                        // in the same cluster are dereferenced in the same way.
546                        CLongArray derefArray = samplePointClusterUV.GetElements().GetArray();
547
548                        for (int j = 0; j < uvElements.GetCount(); ++j)
549                        {
550                                CDoubleArray curUVW(uvElements.GetItem(j));
551                                size_t samplerIndex = derefArray[j];
552                                samplerUVs[samplerIndex].x = curUVW[0];//u
553                                samplerUVs[samplerIndex].y = 1.0f - curUVW[1];//v (invert)
554                                samplerUVs[samplerIndex].z = curUVW[2];//w
555
556                                if (!hasU && curUVW[0] > 0)
557                                        hasU = true;
558                                if (!hasV && curUVW[1] > 0)
559                                        hasV = true;
560                                if (!hasW && curUVW[2] > 0)
561                                        hasW = true;
562
563                        }
564                       
565                        // save dimensions
566                        mCurrentTextureCoordDimensions.push_back(
567                                (hasU?1:0) + (hasV?1:0) + (hasW?1:0));
568
569        }
570
571
572        // do we have vertex colours?
573        ClusterProperty vertexColourClusterProperty = xsiMesh->mesh.GetCurrentVertexColor();
574        if (vertexColourClusterProperty.IsValid())
575            mCurrentHasVertexColours = true;
576                else
577                        mCurrentHasVertexColours = false;
578
579               
580                /* Create any ProtoSubMeshes which don't exist yet for the
581                 * materials in question, and define the PolygonCluster map
582                 */
583                // Main material (will never exist if not merging submeshes)
584                String materialName = mMaterialPrefix +
585                        XSItoOgre(xsiMesh->obj.GetMaterial().GetName());
586                registerMaterial(materialName, xsiMesh->obj.GetMaterial());
587               
588                mMainProtoMesh = createOrRetrieveProtoSubMesh(
589                        materialName,
590                        XSItoOgre(xsiMesh->obj.GetName()),
591                        mCurrentTextureCoordDimensions,
592                        mCurrentHasVertexColours);
593               
594                // For each polygon cluster
595        CRefArray polygonClusters;
596        // Filter to 'poly' types
597        xsiMesh->mesh.GetClusters().Filter(siPolygonCluster, CStringArray(), L"",
598                        polygonClusters);
599                mPolygonToProtoSubMeshList.clear();
600        for(i = 0; i < polygonClusters.GetCount(); ++i)
601        {
602                        Cluster cluster(polygonClusters[i]);   
603                        // Is the material different for this poly cluster?
604                        if (cluster.GetMaterial() != xsiMesh->obj.GetMaterial())
605                        {
606                                String submatName = mMaterialPrefix +
607                                        XSItoOgre(cluster.GetMaterial().GetName());
608                                registerMaterial(submatName, cluster.GetMaterial());
609                                ProtoSubMesh* ps = createOrRetrieveProtoSubMesh(
610                                        submatName,
611                                        XSItoOgre(cluster.GetName()),
612                                        mCurrentTextureCoordDimensions,
613                                        mCurrentHasVertexColours);
614                                // Each element is a polygon index
615                                CLongArray elems = cluster.GetElements().GetArray();
616                                for (int p = 0; p < elems.GetCount(); ++p)
617                                {
618                                        mPolygonToProtoSubMeshList[elems[p]] = ps;
619                                }
620                        }
621                }
622
623                return true;
624
625
626        }
627        //-----------------------------------------------------------------------
628        void XsiMeshExporter::postprocessPolygonMesh(PolygonMeshEntry* xsiMesh)
629        {
630                // clear all position index remaps, incase merged
631                for (ProtoSubMeshList::iterator p = mProtoSubmeshList.begin();
632                        p != mProtoSubmeshList.end(); ++p)
633                {
634                        ProtoSubMesh* ps = p->second;
635                        ps->posIndexRemap.clear();
636                }
637
638                // free temp UV data now
639                for(SamplerSetList::iterator s = mCurrentSamplerSets.begin();
640                        s != mCurrentSamplerSets.end(); ++s)
641                {
642                        // init sampler points
643                        delete [] *s;
644                }
645                mCurrentSamplerSets.clear();
646                mCurrentTextureCoordDimensions.clear();
647               
648        }
649        //-----------------------------------------------------------------------
650        void XsiMeshExporter::processBoneAssignments(Mesh* pMesh, PolygonMeshEntry* xsiMesh)
651        {
652                // We have to iterate over the clusters which have envelope assignments
653                // then, for each protosubmesh which uses this polymesh, we need to create
654                // a bone assignment for each deformer, not forgetting to add one for
655                // each duplicated copy of this vertex too
656                // We build up a global list of deformers as we go which will get passed
657                // back to the top-level caller to build a skeleton from later
658                CRefArray clusterRefArray;
659                // Filter to 'vertex' types
660                xsiMesh->mesh.GetClusters().Filter(
661                        siVertexCluster,CStringArray(),L"",clusterRefArray);
662
663
664
665                for(int i = 0; i < clusterRefArray.GetCount(); ++i)
666                {
667                        Cluster cluster(clusterRefArray[i]);   
668
669                        CRefArray envelopes = cluster.GetEnvelopes();
670                        for (int e = 0; e < envelopes.GetCount(); ++e)
671                        {
672                                Envelope envelope(envelopes[e]);
673
674                                // Get mapping from cluster element index to geometry position index
675                                CLongArray derefArray = envelope.GetElements(CTime().GetTime()).GetArray();
676
677                                CRefArray deformers = envelope.GetDeformers();
678                                for (int d = 0; d < deformers.GetCount(); ++d)
679                                {
680                                        X3DObject deformer(deformers[d]);
681                                        // Has this deformer been allocated a boneID already?
682                                        String deformerName = XSItoOgre(deformer.GetName());
683                                        DeformerMap::iterator di =
684                                                mXsiDeformerMap.find(deformerName);
685                                        DeformerEntry* deformerEntry;
686                                        bool newDeformerEntry = false;
687                                        bool atLeastOneAssignment = false;
688                                        if (di == mXsiDeformerMap.end())
689                                        {
690                                                deformerEntry = new DeformerEntry(mXsiDeformerMap.size(), deformer);
691                                                deformerEntry->hasVertexAssignments = true;
692                                                newDeformerEntry = true;
693                                        }
694                                        else
695                                        {
696                                                deformerEntry = di->second;
697                                        }
698
699                                        // Get the weights for this deformer
700                                        CDoubleArray weights =
701                                                envelope.GetDeformerWeights(deformer, CTime().GetTime());
702                                        // Weights are in order of cluster elements, we need to dereference
703                                        // those to the original point index using the cluster element array
704                                        for (int w = 0; w < weights.GetCount(); ++w)
705                                        {
706                                                size_t positionIndex = derefArray[w];
707                                                float weight = weights[w];
708                                                // Skip zero weights
709                                                if (weight == 0.0f)
710                                                        continue;
711
712                                                // Locate ProtoSubMeshes which use this mesh
713                                                for (ProtoSubMeshList::iterator psi = mProtoSubmeshList.begin();
714                                                        psi != mProtoSubmeshList.end(); ++psi)
715                                                {
716                                                        ProtoSubMesh* ps = psi->second;
717                                                        ProtoSubMesh::PolygonMeshOffsetMap::iterator poli =
718                                                                ps->polygonMeshOffsetMap.find(xsiMesh);
719                                                        if (poli != ps->polygonMeshOffsetMap.end())
720                                                        {
721                                                                // adjust index based on merging
722                                                                size_t adjIndex = positionIndex + poli->second;
723                                                                // look up real index
724                                                                // If it doesn't exist, it's probably on a seam
725                                                                // between clusters and we can safely skip it
726                                                                IndexRemap::iterator remi = ps->posIndexRemap.find(adjIndex);
727                                                                if (remi != ps->posIndexRemap.end())
728                                                                {
729
730                                                                        size_t vertIndex = remi->second;
731                                                                        bool moreVerts = true;
732                                                                        // add UniqueVertex and clones
733                                                                        while (moreVerts)
734                                                                        {
735                                                                                UniqueVertex& vertex = ps->uniqueVertices[vertIndex];
736                                                                                VertexBoneAssignment vba;
737                                                                                vba.boneIndex = deformerEntry->boneID;
738                                                                                vba.vertexIndex = vertIndex;
739                                                                                vba.weight = weight;
740                                                                                ps->boneAssignments.insert(
741                                                                                        Mesh::VertexBoneAssignmentList::value_type(vertIndex, vba));
742                                                                                atLeastOneAssignment = true;
743
744                                                                                if (vertex.nextIndex == 0)
745                                                                                {
746                                                                                        moreVerts = false;
747                                                                                }
748                                                                                else
749                                                                                {
750                                                                                        vertIndex = vertex.nextIndex;
751                                                                                }
752                                                                        }
753                                                                }
754
755                                                        }
756                                                }
757
758
759
760                                        }
761
762                                        // Only add new deformer if we actually had any assignments
763                                        if (newDeformerEntry && atLeastOneAssignment)
764                                        {
765                                                mXsiDeformerMap[deformerName] = deformerEntry;
766                                        }
767
768
769
770                                       
771                                }
772                               
773
774                        }
775                }
776
777
778        }
779        //-----------------------------------------------------------------------
780        void XsiMeshExporter::processShapeKeys(Mesh* pMesh, PolygonMeshEntry* xsiMesh)
781        {
782                // ShapeKeys are kept underneath clusters
783                // The clusters are point clusters, not poly clusters like those used
784                // to define materials
785                // Each point cluster identifies the list of points involved, and the shape key
786                // contains the offsets for that key
787                // Like bone assignments, we have to ensure we add keys for duplicated points
788
789                // Get points & vertices incase we need to convert from local reference frame
790                CPointRefArray pointsArray = xsiMesh->mesh.GetPoints();
791                CVertexRefArray verticesArray = xsiMesh->mesh.GetVertices();
792
793        CRefArray clusterRefArray;
794        // Filter to 'pnt' types
795        xsiMesh->mesh.GetClusters().Filter(
796                        siVertexCluster,CStringArray(),L"",clusterRefArray);
797
798                for(int i = 0; i < clusterRefArray.GetCount(); ++i)
799                {
800                        Cluster cluster(clusterRefArray[i]);
801
802                        // Cluster elements are the vertex indices affected
803                        CClusterElementArray vertexIndexArray = cluster.GetElements();
804
805                        CRefArray clusterProperties = cluster.GetProperties();
806                        for (int p = 0; p < clusterProperties.GetCount(); ++p)
807                        {
808                                ClusterProperty prop(clusterProperties[p]);
809                                // Pull out only shape keys
810                                if (prop.GetPropertyType() == siClusterPropertyShapeKeyType)
811                                {
812                                        ShapeKey shapeKey(prop);
813
814                                        Parameter keyTypeParam = shapeKey.GetParameter(L"KeyType");
815                                        CValue currMode = keyTypeParam.GetValue();
816                                        /*
817                                        StringUtil::StrStreamType str;
818                                        str << "KeyType = " << (unsigned short)currMode <<
819                                                " siShapeLocalReferenceMode = " << (unsigned short)siShapeLocalReferenceMode <<
820                                                " siShapeAbsoluteReferenceMode = " << (unsigned short)siShapeAbsoluteReferenceMode <<
821                                                " siShapeObjectReferenceMode = " << (unsigned short)siShapeObjectReferenceMode;
822                                        LogOgreAndXSI(str.str());
823                                        */
824
825                                        // XSI bug? siShapeReferenceMode enum doesn't match runtime values
826                                        // Local = 1, Absolute = 0, Object = 2 in real life
827                                        // Logged with Softimage as UDEV00203965
828                                        bool isLocalSpace =
829                                                ((unsigned short)currMode) == 1; //siShapeLocalReferenceMode;
830                                        bool isGlobalSpace =
831                                                ((unsigned short)currMode) == 0;//siShapeAbsoluteReferenceMode;
832
833                                        LogOgreAndXSI("Found shape key " + XSItoOgre(shapeKey.GetName()));
834                                        // elements of property are the offsets, a double array of values
835                                        CClusterPropertyElementArray shapeElements = shapeKey.GetElements();
836
837                                        // Locate ProtoSubMeshes which use this mesh
838                                        for (ProtoSubMeshList::iterator psi = mProtoSubmeshList.begin();
839                                                psi != mProtoSubmeshList.end(); ++psi)
840                                        {
841                                                ProtoSubMesh* ps = psi->second;
842                                                ProtoSubMesh::PolygonMeshOffsetMap::iterator poli =
843                                                        ps->polygonMeshOffsetMap.find(xsiMesh);
844                                                if (poli != ps->polygonMeshOffsetMap.end())
845                                                {
846                                                        // remap from mesh vertex index to proto vertex index
847                                                        size_t indexAdjustment = poli->second;
848
849                                                        // Create a new pose, target is implied by proto, final
850                                                        // index to be determined later including merging
851                                                        Pose pose(0, XSItoOgre(shapeKey.GetName()));
852
853                                                        // Iterate per vertex affected
854                                                        for (int xi = 0; xi < vertexIndexArray.GetCount(); ++xi)
855                                                        {
856                                                                // Index
857                                                                size_t positionIndex = vertexIndexArray.GetItem(xi);
858                                                                // Now get offset
859                                                                CDoubleArray xsiOffset = shapeElements.GetItem(xi);
860                                                                Vector3 offset(xsiOffset[0], xsiOffset[1], xsiOffset[2]);
861
862                                                                // Skip zero offsets
863                                                                if (offset == Vector3::ZERO)
864                                                                        continue;
865
866
867                                                                if (isLocalSpace)
868                                                                {
869                                                                        // Local reference mode -> object space
870                                                                        // Local mode is the most popular since in XSI
871                                                                        // it plays nice with skeletal animation, but
872                                                                        // it's relative to the _point's_ local space
873
874                                                                        // Get local axes
875                                                                        // XSI defines local space as:
876                                                                        // Y = vertex normal
877                                                                        // X = normalised projection of first edge
878                                                                        //     from vertex onto normal plane
879                                                                        // Z = cross product of above
880                                                                        Point point(pointsArray[positionIndex]);
881                                                                        bool normalValid;
882                                                                        Vector3 localY = XSItoOgre(point.GetNormal(normalValid));
883                                                                        Vertex vertex(verticesArray.GetItem(positionIndex));
884                                                                        CEdgeRefArray edgeArray = vertex.GetNeighborEdges();
885                                                                        if (normalValid && edgeArray.GetCount() > 0)
886                                                                        {
887
888                                                                                Edge edge(edgeArray[0]);
889                                                                                CVertexRefArray verticesOnEdge = edge.GetNeighborVertices();
890                                                                                Vertex otherVertex =
891                                                                                        (verticesOnEdge[0] == vertex) ?
892                                                                                        verticesOnEdge[1] : verticesOnEdge[0];
893                                                                                Vector3 edgeVector
894                                                                                        = XSItoOgre(otherVertex.GetPosition())
895                                                                                                - XSItoOgre(vertex.GetPosition());
896                                                                                // Project the vector onto the normal plane (d irrelevant)
897                                                                                Plane normPlane(localY, 0);
898                                                                                Vector3 localX = normPlane.projectVector(edgeVector);
899                                                                                localX.normalise();
900
901                                                                                Vector3 localZ = localX.crossProduct(localY);
902
903                                                                                // multiply out position by local axes to form
904                                                                                // final position
905                                                                                offset = (localX * offset.x) +
906                                                                                        (localY * offset.y) +
907                                                                                        (localZ * offset.z);
908
909                                                                        }
910
911                                                                }
912                                                               
913                                                                if (!isGlobalSpace)
914                                                                {
915                                                                        // shape is in object space, if object is parented
916                                                                        // by a null or a static bone, we need to adjust the
917                                                                        // shape offset since this inherited transform is
918                                                                        // baked into the base OGRE mesh (to preserve
919                                                                        // relative positioning of parts)
920
921                                                                        // If object is parented
922                                                                        // Don't know if anyone really uses this
923                                                                        // Convert global to object space
924                                                                        MATH::CTransformation xform =
925                                                                                xsiMesh->obj.GetKinematics().GetGlobal().GetTransform();
926                                                                        MATH::CVector3 off(offset.x, offset.y, offset.z);
927                                                                        off.MulByTransformationInPlace(xform);
928                                                                        offset = XSItoOgre(off);
929
930                                                                }
931
932
933                                                                // adjust index based on merging
934                                                                size_t adjIndex = positionIndex + indexAdjustment;
935                                                                // look up real index
936                                                                // If it doesn't exist, it's probably on a seam
937                                                                // between clusters and we can safely skip it
938                                                                IndexRemap::iterator remi = ps->posIndexRemap.find(adjIndex);
939                                                                if (remi != ps->posIndexRemap.end())
940                                                                {
941
942                                                                        size_t vertIndex = remi->second;
943                                                                        bool moreVerts = true;
944
945
946                                                                        // add UniqueVertex and clones
947                                                                        while (moreVerts)
948                                                                        {
949                                                                                UniqueVertex& vertex = ps->uniqueVertices[vertIndex];
950
951                                                                                // Create a vertex pose entry
952                                                                                pose.addVertex(vertIndex, offset);
953
954                                                                                if (vertex.nextIndex == 0)
955                                                                                {
956                                                                                        moreVerts = false;
957                                                                                }
958                                                                                else
959                                                                                {
960                                                                                        vertIndex = vertex.nextIndex;
961                                                                                }
962                                                                        } // more duplicate verts
963                                                                } // found remap?
964                                                        } // for each vertex affected
965
966                                                        // Add pose to proto
967                                                        ps->poseList.push_back(pose);
968
969                                                        // record that we used this shape key
970                                                        ps->shapeKeys.Add(shapeKey);
971
972
973                                                } // proto found?
974                                        }// for each proto
975                                } // shape key cluster property?
976                        } // for each cluster property
977                } // for each cluster
978
979        }
980        //-----------------------------------------------------------------------
981        void XsiMeshExporter::buildShapeClipList(ShapeClipList& listToPopulate)
982        {
983                // Process all mixers
984                Model root = mXsiApp.GetActiveSceneRoot();
985                if (root.HasMixer())
986                        buildShapeClipList(root.GetMixer(), listToPopulate);
987
988                // Get all child models (recursive)
989                CRefArray models = root.GetModels();
990                for (int m = 0; m < models.GetCount(); ++m)
991                {
992                        Model model(models[m]);
993                        if (model.HasMixer())
994                                buildShapeClipList(model.GetMixer(), listToPopulate);
995                }
996
997        }
998        //-----------------------------------------------------------------------
999        void XsiMeshExporter::buildShapeClipList(ClipContainer& container,
1000                ShapeClipList& listToPopulate)
1001        {
1002                CRefArray clips = container.GetClips();
1003                for (int c = 0; c < clips.GetCount(); ++c)
1004                {
1005                        if (clips[c].IsA(siClipContainerID))
1006                        {
1007                                ClipContainer container(clips[c]);
1008                                // cascade
1009                                buildShapeClipList(container, listToPopulate);
1010                        }
1011                        else
1012                        {
1013
1014                                XSI::Clip clip(clips[c]);
1015                                XSI::CString clipType = clip.GetType();
1016                                if (clip.GetType() == siClipShapeType)
1017                                {
1018                                        XSI::TimeControl timeControl = clip.GetTimeControl();
1019                                        ShapeClipEntry sce;
1020                                        sce.clip = clip;
1021                                        sce.startFrame = timeControl.GetStartOffset();
1022                                        long length = (1.0 / timeControl.GetScale()) *
1023                                                (timeControl.GetClipOut() - timeControl.GetClipIn() + 1);
1024                                        sce.endFrame = sce.startFrame + length - 1;
1025
1026                                        // Find link to shape
1027                                        sce.keytoPose = 0;
1028                                        ActionSource source(clip.GetSource());
1029                                        CRefArray sourceItems = source.GetItems();
1030                                        assert (sourceItems.GetCount() == 1 && "More than one source item on shape clip!");
1031                                        AnimationSourceItem sourceItem(sourceItems[0]);
1032                                        // Source is the shape key
1033                                        // Locate this in the list we built while building poses
1034                                        for (ShapeKeyMapping::iterator skm = mShapeKeyMapping.begin();
1035                                                skm != mShapeKeyMapping.end(); ++skm)
1036                                        {
1037                                                ShapeKeyToPoseEntry& mapping = *skm;
1038                                                if(mapping.shapeKey == sourceItem.GetSource())
1039                                                {
1040                                                        // bingo
1041                                                        sce.keytoPose = &(*skm);
1042                                                }
1043                                        }
1044
1045                                        listToPopulate.push_back(sce);
1046
1047                                }
1048                        }
1049
1050                }
1051
1052
1053        }
1054        //-----------------------------------------------------------------------
1055        void XsiMeshExporter::exportAnimations(Mesh* pMesh, AnimationList& animList,
1056                Real fps)
1057        {
1058                ShapeClipList clipList;
1059                buildShapeClipList(clipList);
1060                // Add all animations
1061                for (AnimationList::iterator i = animList.begin(); i != animList.end(); ++i)
1062                {
1063                        // For each animation, we want to search for all shape clips using a
1064                        // shape key which has been used
1065                        AnimationEntry& animEntry = *i;
1066                        Animation* anim = 0;
1067
1068                        // Iterate per submesh since we want to collect a track per submesh
1069                        // Iterate over the 'target index' which is submesh index + 1
1070                        for (ushort targetIndex = 1; targetIndex <= pMesh->getNumSubMeshes(); ++targetIndex)
1071                        {
1072                                // find all shape clips for this submesh overlapping this time period
1073                                // we'll clamp the clip too
1074                                ShapeClipList submeshClipList;
1075                                std::set<long> keyframeList;
1076
1077                                deriveShapeClipAndKeyframeList(targetIndex, animEntry, clipList,
1078                                        submeshClipList, keyframeList);
1079
1080                                if (!submeshClipList.empty())
1081                                {
1082
1083                                        // Create animation if we haven't already
1084                                        if (!anim)
1085                                        {
1086                                                Real len = (float)(animEntry.endFrame - animEntry.startFrame + 1) / fps;
1087                                                anim = pMesh->createAnimation(animEntry.animationName, len);
1088                                        }
1089                                       
1090                                        // Create track
1091                                        VertexAnimationTrack* track =
1092                                                anim->createVertexTrack(targetIndex, VAT_POSE);
1093                                       
1094                                        // Now sample all the clips on all the keyframes
1095                                        for (std::set<long>::iterator k = keyframeList.begin();
1096                                                k != keyframeList.end(); ++k)
1097                                        {
1098                                                // Create a key
1099                                                long frameNum = *k;
1100                                                Real keyTime = (float)(frameNum - animEntry.startFrame) / fps;
1101                                                VertexPoseKeyFrame* keyFrame =
1102                                                        track->createVertexPoseKeyFrame(keyTime);
1103
1104                                                // Sample all the clips
1105                                                for (ShapeClipList::iterator c = submeshClipList.begin();
1106                                                        c != submeshClipList.end(); ++c)
1107                                                {
1108                                                        ShapeClipEntry& sce = *c;
1109                                                        if(frameNum >= sce.startFrame &&
1110                                                                frameNum <= sce.endFrame)
1111                                                        {
1112
1113                                                                // map the keyframe number to a local number
1114                                                                long localFrameNum = frameNum - sce.startFrame *
1115                                                                        sce.clip.GetTimeControl().GetScale();
1116
1117                                                                // sample pose influences
1118                                                                // Iterate over the animated parameters, find a 'weight' fcurve entry
1119                                                                bool fcurveFound = false;
1120                                                                CRefArray params = sce.clip.GetAnimatedParameters();
1121                                                                for (int p = 0; p < params.GetCount(); ++p)
1122                                                                {
1123                                                                        Parameter param(params[p]);
1124                                                                        if (param.GetSource().IsA(siFCurveID))
1125                                                                        {
1126                                                                                fcurveFound = true;
1127                                                                                FCurve fcurve(param.GetSource());
1128                                                                                CValue val = fcurve.Eval(localFrameNum);
1129                                                                                if ((float)val != 0.0f)
1130                                                                                {
1131                                                                                        keyFrame->addPoseReference(
1132                                                                                                sce.keytoPose->poseIndex, val);
1133                                                                                }
1134                                                                               
1135                                                                        }
1136                                                                }
1137
1138                                                                if (!fcurveFound)
1139                                                                {
1140                                                                        // No fcurves, so just assume 1.0 weight since that's
1141                                                                        // how XSI deals with it
1142                                                                        keyFrame->addPoseReference(sce.keytoPose->poseIndex, 1.0f);
1143
1144                                                                }
1145                                                        }
1146                                                }
1147                                        }
1148                                       
1149                                }
1150
1151                        }
1152                }
1153
1154        }
1155        //-----------------------------------------------------------------------
1156        void XsiMeshExporter::deriveShapeClipAndKeyframeList(ushort targetIndex,
1157                AnimationEntry& animEntry, ShapeClipList& inClipList,
1158                ShapeClipList& outClipList, std::set<long>& keyFrameList)
1159        {
1160                for (ShapeClipList::iterator sci = inClipList.begin();
1161                        sci != inClipList.end(); ++sci)
1162                {
1163                        ShapeClipEntry& sce = *sci;
1164
1165                        if (sce.startFrame <= animEntry.endFrame &&
1166                                sce.endFrame >= animEntry.startFrame &&
1167                                sce.keytoPose->targetHandle == targetIndex)
1168                        {
1169                                // Clip overlaps with the animation sampling area and
1170                                // applies to this submesh
1171                                ShapeClipEntry newClipEntry;
1172                                newClipEntry.startFrame = std::max(sce.startFrame, animEntry.startFrame);
1173                                newClipEntry.endFrame = std::min(sce.endFrame, animEntry.endFrame);
1174                                newClipEntry.clip = sce.clip;
1175                                newClipEntry.keytoPose = sce.keytoPose;
1176                                outClipList.push_back(newClipEntry);
1177
1178                                // Iterate over the animated parameters, find a 'weight' fcurve entry
1179                                CRefArray params = sce.clip.GetAnimatedParameters();
1180                                for (int p = 0; p < params.GetCount(); ++p)
1181                                {
1182                                        Parameter param(params[p]);
1183                                        if (param.GetSource().IsA(siFCurveID))
1184                                        {
1185                                                FCurve fcurve(param.GetSource());
1186                                                CRefArray keys = fcurve.GetKeys();
1187                                                for (int k = 0; k < keys.GetCount(); ++k)
1188                                                {
1189                                                        FCurveKey key(keys[k]);
1190                                                        // convert from key time to global frame number
1191                                                        CTime time = key.GetTime();
1192                                                        long frameNum = (long)((double)(time.GetTime() + sce.startFrame)
1193                                                                / sce.clip.GetTimeControl().GetScale());
1194                                                        keyFrameList.insert(frameNum);
1195                                                }
1196                               
1197
1198                                        }
1199                                }
1200
1201                        }
1202                }
1203                // Always sample start & end frames
1204                keyFrameList.insert(animEntry.startFrame);
1205                keyFrameList.insert(animEntry.endFrame);
1206
1207        }
1208        //-----------------------------------------------------------------------
1209        void XsiMeshExporter::exportProtoSubMeshes(Mesh* pMesh)
1210        {
1211                // Take the list of ProtoSubMesh instances and bake a SubMesh per
1212                // instance, then clear the list
1213
1214                for (ProtoSubMeshList::iterator i = mProtoSubmeshList.begin();
1215                        i != mProtoSubmeshList.end(); ++i)
1216                {
1217                        // export each one
1218                        exportProtoSubMesh(pMesh, i->second);
1219
1220                        // free it
1221                        delete i->second;
1222                }
1223                mProtoSubmeshList.clear();
1224        }
1225        //-----------------------------------------------------------------------
1226        void XsiMeshExporter::exportProtoSubMesh(Mesh* pMesh, ProtoSubMesh* proto)
1227        {
1228                // Skip protos which have ended up empty
1229                if (proto->indices.empty())
1230                        return;
1231
1232        SubMesh* sm = 0;
1233        if (proto->name.empty())
1234        {
1235            // anonymous submesh
1236            sm = pMesh->createSubMesh();
1237        }
1238        else
1239        {
1240            // named submesh
1241            sm = pMesh->createSubMesh(proto->name);
1242        }
1243
1244        // Set material
1245        sm->setMaterialName(proto->materialName);
1246        // never use shared geometry
1247        sm->useSharedVertices = false;
1248        sm->vertexData = new VertexData();
1249        // always do triangle list
1250        sm->indexData->indexCount = proto->indices.size();
1251               
1252                sm->vertexData->vertexCount = proto->uniqueVertices.size();
1253        // Determine index size
1254        bool use32BitIndexes = false;
1255        if (proto->uniqueVertices.size() > 65536)
1256        {
1257            use32BitIndexes = true;
1258        }
1259
1260        sm->indexData->indexBuffer =
1261            HardwareBufferManager::getSingleton().createIndexBuffer(
1262            use32BitIndexes ? HardwareIndexBuffer::IT_32BIT : HardwareIndexBuffer::IT_16BIT,
1263            sm->indexData->indexCount,
1264            HardwareBuffer::HBU_STATIC_WRITE_ONLY);
1265        if (use32BitIndexes)
1266        {
1267            uint32* pIdx = static_cast<uint32*>(
1268                sm->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
1269            writeIndexes(pIdx, proto->indices);
1270            sm->indexData->indexBuffer->unlock();
1271        }
1272        else
1273        {
1274            uint16* pIdx = static_cast<uint16*>(
1275                sm->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
1276            writeIndexes(pIdx, proto->indices);
1277            sm->indexData->indexBuffer->unlock();
1278        }
1279
1280
1281        // define vertex declaration
1282        unsigned buf = 0;
1283        size_t offset = 0;
1284                // always add position and normal
1285        sm->vertexData->vertexDeclaration->addElement(buf, offset, VET_FLOAT3, VES_POSITION);
1286        offset += VertexElement::getTypeSize(VET_FLOAT3);
1287                // Split vertex data after position if poses present
1288                if (!proto->poseList.empty())
1289                {
1290                        buf++;
1291                        offset = 0;
1292                }
1293        sm->vertexData->vertexDeclaration->addElement(buf, offset, VET_FLOAT3, VES_NORMAL);
1294        offset += VertexElement::getTypeSize(VET_FLOAT3);
1295        // split vertex data here if animated
1296        if (pMesh->hasSkeleton())
1297        {
1298            buf++;
1299            offset = 0;
1300        }
1301                // Optional vertex colour
1302        if(proto->hasVertexColours)
1303        {
1304            sm->vertexData->vertexDeclaration->addElement(buf, offset, VET_COLOUR, VES_DIFFUSE);
1305            offset += VertexElement::getTypeSize(VET_COLOUR);
1306        }
1307        // Define UVs
1308        for (unsigned short uvi = 0; uvi < proto->textureCoordDimensions.size(); ++uvi)
1309        {
1310                        VertexElementType uvType =
1311                                VertexElement::multiplyTypeCount(
1312                                        VET_FLOAT1, proto->textureCoordDimensions[uvi]);
1313            sm->vertexData->vertexDeclaration->addElement(
1314                                buf, offset, uvType, VES_TEXTURE_COORDINATES, uvi);
1315            offset += VertexElement::getTypeSize(uvType);
1316        }
1317
1318        // create & fill buffer(s)
1319        for (unsigned short b = 0; b <= sm->vertexData->vertexDeclaration->getMaxSource(); ++b)
1320        {
1321            createVertexBuffer(sm->vertexData, b, proto->uniqueVertices);
1322        }
1323
1324                // deal with any bone assignments
1325                if (!proto->boneAssignments.empty())
1326                {
1327                        // rationalise first (normalises and strips out any excessive bones)
1328                        sm->parent->_rationaliseBoneAssignments(
1329                                sm->vertexData->vertexCount, proto->boneAssignments);
1330
1331                        for (Mesh::VertexBoneAssignmentList::iterator bi = proto->boneAssignments.begin();
1332                                bi != proto->boneAssignments.end(); ++bi)
1333                        {
1334                                sm->addBoneAssignment(bi->second);
1335                        }
1336                }
1337
1338                // poses
1339                // derive target index (current submesh index + 1 since 0 is shared geom)
1340                ushort targetIndex = pMesh->getNumSubMeshes();
1341                ushort sk = 0;
1342                for (std::list<Pose>::iterator pi = proto->poseList.begin();
1343                        pi != proto->poseList.end(); ++pi, ++sk)
1344                {
1345                        Pose* pose = pMesh->createPose(targetIndex, pi->getName());
1346                        Pose::VertexOffsetIterator vertIt =
1347                                pi->getVertexOffsetIterator();
1348                        while (vertIt.hasMoreElements())
1349                        {
1350                                pose->addVertex(vertIt.peekNextKey(), vertIt.peekNextValue());
1351                                vertIt.getNext();
1352                        }
1353
1354                        // record shape key to pose mapping for animation later
1355                        ShapeKeyToPoseEntry se;
1356                        se.shapeKey = proto->shapeKeys[sk];
1357                        se.poseIndex = pMesh->getPoseCount() - 1;
1358                        se.targetHandle = targetIndex;
1359                        mShapeKeyMapping.push_back(se);
1360
1361                }
1362
1363        }
1364        //-----------------------------------------------------------------------
1365        void XsiMeshExporter::buildPolygonMeshList(bool includeChildren)
1366        {
1367                Selection sel(mXsiApp.GetSelection());
1368                if (sel.GetCount() == 0)
1369                {
1370                        // Whole scene
1371                        // Derive the scene root
1372                        X3DObject sceneRoot(mXsiApp.GetActiveSceneRoot());
1373                        findPolygonMeshes(sceneRoot, true);
1374                }
1375                else
1376                {
1377                        // iterate over selection
1378                        for (int i = 0; i < sel.GetCount(); ++i)
1379                        {
1380                                X3DObject obj(sel[i]);
1381                                findPolygonMeshes(obj,includeChildren);
1382                        }
1383                }
1384        }
1385        //-----------------------------------------------------------------------
1386        void XsiMeshExporter::findPolygonMeshes(X3DObject& x3dObj, bool recurse)
1387        {
1388                // Check validity of current object
1389                if (!x3dObj.IsValid())
1390                {
1391                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
1392                                "Invalid X3DObject found",
1393                                "XsiMeshExporter::exportX3DObject");
1394                }
1395                // Log a message in script window
1396                CString name = x3dObj.GetName() ;
1397                LogOgreAndXSI(L"-- Traversing " +  name) ;
1398
1399
1400                // locate any geometry
1401                if (!x3dObj.IsA(siCameraID) &&
1402                        !x3dObj.IsA(siLightID) &&
1403                        !x3dObj.IsA(siNullID) &&
1404                        !x3dObj.IsA(siModelID))
1405                {
1406                        Primitive prim(x3dObj.GetActivePrimitive());
1407                        if (prim.IsValid())
1408                        {
1409                                Geometry geom(prim.GetGeometry());
1410                                if (geom.GetRef().GetClassID() == siPolygonMeshID)
1411                                {
1412                                        // add it to the list
1413                                        PolygonMesh pmesh(geom);
1414                                        mXsiPolygonMeshList.insert(
1415                                                new PolygonMeshEntry(pmesh, x3dObj));
1416
1417                                        LogOgreAndXSI(L"-- Queueing " +  name) ;
1418                                }
1419                        }
1420
1421                }
1422
1423                // Cascade into children
1424                if (recurse)
1425                {
1426                        CRefArray children = x3dObj.GetChildren();
1427
1428                        for(long i = 0; i < children.GetCount(); i++)
1429                        {
1430                                X3DObject childObj = children[i];
1431                                findPolygonMeshes(childObj, recurse);
1432                        }
1433                }
1434
1435        }
1436    //-----------------------------------------------------------------------
1437        void XsiMeshExporter::cleanupPolygonMeshList(void)
1438        {
1439                for (PolygonMeshList::iterator pm = mXsiPolygonMeshList.begin();
1440                        pm != mXsiPolygonMeshList.end(); ++pm)
1441                {
1442                        delete *pm;
1443                }
1444                mXsiPolygonMeshList.clear();
1445        }
1446        //-----------------------------------------------------------------------
1447        void XsiMeshExporter::cleanupDeformerMap(void)
1448        {
1449                for (DeformerMap::iterator d = mXsiDeformerMap.begin();
1450                        d != mXsiDeformerMap.end(); ++d)
1451                {
1452                        delete d->second;
1453                }
1454                mXsiDeformerMap.clear();
1455        }
1456        //-----------------------------------------------------------------------
1457        void XsiMeshExporter::cleanupMaterialMap(void)
1458        {
1459                for (MaterialMap::iterator d = mXsiMaterialMap.begin();
1460                        d != mXsiMaterialMap.end(); ++d)
1461                {
1462                        delete d->second;
1463                }
1464                mXsiMaterialMap.clear();
1465        }
1466        //-----------------------------------------------------------------------
1467        void XsiMeshExporter::deriveSamplerIndices(const Triangle& tri,
1468                const PolygonFace& face, size_t* samplerIndices)
1469        {
1470                //We want to find what is the SampleIndex associated with 3
1471                //vertex in a Triangle
1472                CPointRefArray facePoints = face.GetPoints();
1473
1474                //Get the position of the 3 vertex in the triangle
1475                MATH::CVector3Array triPos = tri.GetPositionArray();
1476
1477                //Get the position of the N Points in the polygon
1478                MATH::CVector3Array facePos = facePoints.GetPositionArray();
1479
1480                //To know if the 3 vertex have a point in the same position
1481                bool found[3];
1482                found[0] = false;
1483                found[1] = false;
1484                found[2] = false;
1485
1486                int p,t;
1487                //For the 3 triangle vertices
1488                for(t=0; t<3 ; t++)
1489                {       //for each polygon point
1490                        for(p=0; p<facePos.GetCount() && !found[t]; p++)
1491                        {
1492                                //Check if the position is the same
1493                                if(triPos[t] == facePos[p])
1494                                {
1495                                        //if so, we know the PolygonPointIndex of the TriangleVertex
1496                                        //then, we must find what is the sample index associated
1497                                        //with this Point
1498                                        samplerIndices[t] =
1499                                                getSamplerIndex(Facet(face), facePoints[p]);
1500                                        found[t] = true;
1501                                }
1502                        }
1503
1504                }
1505
1506                if (!found[0] || !found[1] || !found[2] )
1507                {
1508                        // Problem!
1509                        LogOgreAndXSI(L"!! Couldn't find a matching UV point!");
1510                }
1511
1512        }
1513        //-----------------------------------------------------------------------
1514        size_t XsiMeshExporter::getSamplerIndex(const Facet &f, const Point &p)
1515        {
1516                //This function check if a Sample is shared by a Facet and a Point
1517                //just by using the operator=
1518                //Only one Sample can be shared.
1519
1520                Sample curFacetSample;
1521                CSampleRefArray facetSamples( f.GetSamples() );
1522                CSampleRefArray pointSamples( p.GetSamples() );
1523
1524                for(int i = 0; i < facetSamples.GetCount(); i++ )
1525                {
1526
1527                        curFacetSample = Sample( facetSamples[i] );
1528
1529                        for(int j = 0; j < pointSamples.GetCount(); j++)
1530                        {
1531                                if(curFacetSample == Sample(pointSamples[j]))
1532                                {
1533                                        return curFacetSample.GetIndex();
1534                                }
1535                        }
1536                }
1537                // Problem!
1538                mXsiApp.LogMessage(L"!! Couldn't find a matching sample point!");
1539                return 0;
1540        }
1541    //-----------------------------------------------------------------------
1542    template <typename T>
1543    void XsiMeshExporter::writeIndexes(T* buf, IndexList& indexes)
1544    {
1545        IndexList::const_iterator i, iend;
1546        iend = indexes.end();
1547        for (i = indexes.begin(); i != iend; ++i)
1548        {
1549            *buf++ = static_cast<T>(*i);
1550        }
1551    }
1552    //-----------------------------------------------------------------------
1553    void XsiMeshExporter::createVertexBuffer(VertexData* vd,
1554                unsigned short bufIdx, UniqueVertexList& uniqueVertexList)
1555    {
1556        HardwareVertexBufferSharedPtr vbuf =
1557                        HardwareBufferManager::getSingleton().createVertexBuffer(
1558                vd->vertexDeclaration->getVertexSize(bufIdx),
1559                vd->vertexCount,
1560                HardwareBuffer::HBU_STATIC_WRITE_ONLY);
1561        vd->vertexBufferBinding->setBinding(bufIdx, vbuf);
1562        size_t vertexSize = vd->vertexDeclaration->getVertexSize(bufIdx);
1563
1564        char* pBase = static_cast<char*>(
1565                                vbuf->lock(HardwareBuffer::HBL_DISCARD));
1566
1567        VertexDeclaration::VertexElementList elems =
1568                        vd->vertexDeclaration->findElementsBySource(bufIdx);
1569        VertexDeclaration::VertexElementList::iterator ei, eiend;
1570        eiend = elems.end();
1571        float* pFloat;
1572        RGBA* pRGBA;
1573
1574        UniqueVertexList::iterator srci = uniqueVertexList.begin();
1575
1576        for (size_t v = 0; v < vd->vertexCount; ++v, ++srci)
1577        {
1578            for (ei = elems.begin(); ei != eiend; ++ei)
1579            {
1580                VertexElement& elem = *ei;
1581                switch(elem.getSemantic())
1582                {
1583                case VES_POSITION:
1584                    elem.baseVertexPointerToElement(pBase, &pFloat);
1585                    *pFloat++ = srci->position.x;
1586                    *pFloat++ = srci->position.y;
1587                    *pFloat++ = srci->position.z;
1588                    break;
1589                case VES_NORMAL:
1590                    elem.baseVertexPointerToElement(pBase, &pFloat);
1591                    *pFloat++ = srci->normal.x;
1592                    *pFloat++ = srci->normal.y;
1593                    *pFloat++ = srci->normal.z;
1594                    break;
1595                case VES_DIFFUSE:
1596                    elem.baseVertexPointerToElement(pBase, &pRGBA);
1597                    *pRGBA = srci->colour;
1598                    break;
1599                case VES_TEXTURE_COORDINATES:
1600                    elem.baseVertexPointerToElement(pBase, &pFloat);
1601                                        for (int t = 0; t < VertexElement::getTypeCount(elem.getType()); ++t)
1602                                        {
1603                                                Real val = srci->uv[elem.getIndex()][t];
1604                                                *pFloat++ = val;
1605                                        }
1606                    break;
1607                }
1608            }
1609            pBase += vertexSize;
1610        }
1611        vbuf->unlock();
1612
1613    }
1614    //-----------------------------------------------------------------------
1615    size_t XsiMeshExporter::createOrRetrieveUniqueVertex(
1616                ProtoSubMesh* proto, size_t positionIndex,
1617                bool positionIndexIsOriginal, const UniqueVertex& vertex)
1618    {
1619                size_t lookupIndex;
1620                if (positionIndexIsOriginal)
1621                {
1622                        // look up the original index
1623                        IndexRemap::iterator remapi =
1624                                proto->posIndexRemap.find(positionIndex);
1625                        if (remapi == proto->posIndexRemap.end())
1626                        {
1627                                // not found, add
1628                                size_t realIndex = proto->uniqueVertices.size();
1629                                // add remap entry so we can find this again
1630                                proto->posIndexRemap[positionIndex] = realIndex;
1631                                proto->uniqueVertices.push_back(vertex);
1632                                return realIndex;
1633                        }
1634                        else
1635                        {
1636                                // Found existing mapping
1637                                lookupIndex = remapi->second;
1638                        }
1639                }
1640                else
1641                {
1642                        // Not an original index, index is real
1643                        lookupIndex = positionIndex;
1644                }
1645
1646                // If we get here, either the position isn't an original index (ie
1647                // we've already found that it doesn't match, and have cascaded)
1648                // or there is an existing entry
1649                // Get existing
1650            UniqueVertex& orig = proto->uniqueVertices[lookupIndex];
1651                // Compare, do we have the same details?
1652                if (orig == vertex)
1653                {
1654                        // ok, they match
1655                        return lookupIndex;
1656                }
1657                else
1658                {
1659            // no match, go to next or create new
1660                if (orig.nextIndex)
1661                {
1662                // cascade to the next candidate (which is a real index, not an original)
1663                return createOrRetrieveUniqueVertex(
1664                                                proto, orig.nextIndex, false, vertex);
1665            }
1666                        else
1667                        {
1668                                // No more cascades to check, must be a new one
1669                    // get new index
1670                size_t realIndex = proto->uniqueVertices.size();
1671                    orig.nextIndex = realIndex;
1672                // create new (NB invalidates 'orig' reference)
1673                proto->uniqueVertices.push_back(vertex);
1674                                // note, don't add to remap, that's only for finding the
1675                                // first entry, nextIndex is used to chain to the others
1676
1677                return realIndex;
1678                        }
1679                }
1680    }
1681    //-----------------------------------------------------------------------
1682        void XsiMeshExporter::registerMaterial(const String& name,
1683                XSI::Material mat)
1684        {
1685                // Check we have a real-time shader based material first
1686                XSI::Parameter rtParam = mat.GetParameter(L"RealTime");
1687               
1688                if(rtParam.GetSource().IsValid() &&
1689                        rtParam.GetSource().IsA(XSI::siShaderID))
1690                {
1691                        MaterialMap::iterator i = mXsiMaterialMap.find(name);
1692                        if (i == mXsiMaterialMap.end())
1693                        {
1694                                // Add this one to the list
1695                                MaterialEntry* matEntry = new MaterialEntry();
1696                                matEntry->name = name;
1697                                matEntry->xsiShader = XSI::Shader(rtParam.GetSource());
1698                                mXsiMaterialMap[name] = matEntry;
1699                        }
1700                }
1701        }
1702}
Note: See TracBrowser for help on using the repository browser.