Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/Tools/3dsmaxExport/OgreExport/src/OgreMaxMeshXMLExport.cpp @ 6

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

=…

File size: 29.4 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 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
26#include "OgreExport.h"
27#include "OgreMaxMeshXMLExport.h"
28#include "OgreMaxVertex.h"
29
30#include "max.h"
31#include "plugapi.h"
32#include "stdmat.h"
33#include "impexp.h"
34#include "CS/BipedApi.h"
35#include "CS/KeyTrack.h"
36#include "CS/phyexp.h"
37#include "iparamb2.h"
38#include "iskin.h"
39
40#include "IGame/IGame.h"
41
42namespace OgreMax
43{
44        MeshXMLExporter::MeshXMLExporter(const Config& config, MaterialMap& map) : m_materialMap(map), OgreMaxExporter(config)
45        {
46                m_createSkeletonLink = false;
47                m_pGame = 0;
48
49                m_currentBoneIndex = 0;                         // used to map bone names to bone indices for vertex assignment and later skeleton export
50        }
51
52        MeshXMLExporter::~MeshXMLExporter()
53        {
54        }
55
56        bool MeshXMLExporter::buildMeshXML(OutputMap& output)
57        {
58                return export(output);
59        }
60
61
62        // "callback" is called in response to the EnumTree() call made below. That call visits every node in the
63        // scene and calls this procedure for each one.
64        int MeshXMLExporter::callback(INode *node) {
65
66                // SKELOBJ_CLASS_ID = 0x9125 = 37157
67                // BIPED_CLASS_ID = 0x9155 = 37205
68                // BIPSLAVE_CONTROL_CLASS_ID = 0x9154 = 37204
69                // BIPBODY_CONTROL_CLASS_ID = 0x9156 = 37206
70                // FOOTPRINT_CLASS_ID = 0x3011 = 12305
71                // DUMMY_CLASS_ID = 0x876234 = 8872500
72
73                TimeValue start = m_i->GetAnimRange().Start();
74                Object *obj = node->EvalWorldState(start).obj;
75                Class_ID cid = obj->ClassID();
76
77                // nodes that have Biped controllers are bones -- ignore the ones that are dummies
78                if (cid == Class_ID(DUMMY_CLASS_ID, 0))
79                        return TREE_CONTINUE;
80
81                Control *c = node->GetTMController();
82                if ((c->ClassID() == BIPSLAVE_CONTROL_CLASS_ID) ||
83                        (c->ClassID() == BIPBODY_CONTROL_CLASS_ID) ||
84                        (c->ClassID() == FOOTPRINT_CLASS_ID)) {
85
86                                if (node->GetParentNode() != NULL) {
87                                        // stick this in the bone-index map for later use
88                                        m_boneIndexMap.insert(std::map< std::string, int >::value_type(std::string(node->GetName()), m_currentBoneIndex++));
89                                }
90
91                                return TREE_CONTINUE;
92                }
93                // if the node cannot be converted to a TriObject (mesh), ignore it
94                if (!obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0)))
95                        return TREE_CONTINUE;
96
97                // create a list of nodes to process
98                if (m_config.getExportSelected()) {
99                        if (node->Selected()) {
100                                m_nodeTab.Append(1, &node);
101                        }
102                }
103                else {
104                        m_nodeTab.Append(1, &node);
105                }
106
107                return TREE_CONTINUE;
108        }
109
110        ////////////////////////////////////////////////////////////////////////////////
111        // Regardless of whether the user chooses to export submesh-per-file or to put
112        // all submeshes in the same file, we will deal with submaterials by creating
113        // "duplicate" vertices based on normal and texcoord differences. In other words,
114        // "unique" vertices will be based on smoothing-group normals (if used, face normals if
115        // not) and face texcoords, not the inherent vertex normals and texcoords.
116        //
117        // The basic concept is the same as used in the MaxScript exporter (as well as
118        // the exporters for other 3D tools): iterate the faces, extracting normal and
119        // texcoord info along with the position and color data; vertices are "unique-ified"
120        // as they are added to the vertex list.
121        ////////////////////////////////////////////////////////////////////////////////
122
123        bool MeshXMLExporter::export(OutputMap& output) {
124
125                try {
126
127                        // write XML to a strstream
128                        std::stringstream of;
129
130                        while (!m_submeshNames.empty())
131                                m_submeshNames.pop();
132
133                        if (m_pGame) {
134                                m_pGame->ReleaseIGame();
135                                m_pGame = 0;
136                        }
137
138                        m_ei->theScene->EnumTree(this);
139
140                        m_pGame = GetIGameInterface();
141                        IGameConversionManager* cm = GetConversionManager();
142                        cm->SetCoordSystem(IGameConversionManager::IGAME_OGL);
143                        m_pGame->InitialiseIGame(m_nodeTab, false);
144                        m_pGame->SetStaticFrame(0);
145                        int nodeCount = m_pGame->GetTopLevelNodeCount();
146
147                        if (nodeCount == 0) {
148                                MessageBox(GetActiveWindow(), "No nodes available to export, aborting...", "Nothing To Export", MB_ICONINFORMATION);
149                                m_pGame->ReleaseIGame();
150                                return false;
151                        }
152
153                        // if we are writing everything to one file, use the name provided when the user first started the export;
154                        // otherwise, create filenames on the basis of the node (submesh) names
155                        std::string fileName;
156                        IGameNode* node = m_pGame->GetTopLevelNode(0);
157                        if (!m_config.getExportMultipleFiles())
158                                fileName = m_config.getExportFilename();
159                        else {
160                                fileName = m_config.getExportPath() + "\\";
161                                fileName += node->GetName();
162                                fileName += ".mesh.xml";
163                        }
164
165                        // write start of XML data
166                        streamFileHeader(of);
167
168                        int nodeIdx = 0;
169                        std::map<std::string, std::string> materialScripts;
170
171                        while (nodeIdx < nodeCount) {
172
173                                std::string mtlName;
174                                IGameNode* node = m_pGame->GetTopLevelNode(nodeIdx);
175                                IGameObject* obj = node->GetIGameObject();
176
177                                // InitializeData() is important -- it performs all of the WSM/time eval for us; no data without it
178                                obj->InitializeData();
179                               
180                                IGameMaterial* mtl = node->GetNodeMaterial();
181                                if (mtl == NULL)
182                                        mtlName = m_config.getDefaultMaterialName();
183                                else
184                                        mtlName = mtl->GetMaterialName();
185
186                                // clean out any spaces the user left in their material name
187                                std::string::size_type pos;
188                                while ((pos = mtlName.find_first_of(' ')) != std::string::npos)
189                                        mtlName.replace(pos, 1, _T("_"));
190
191                                if (materialScripts.find(mtlName) == materialScripts.end()) {
192
193                                        // export new material script
194                                        MaterialExporter mexp(m_config, m_materialMap);
195                                        std::string script;
196
197                                        mexp.buildMaterial(mtl, mtlName, script);
198                                        materialScripts[mtlName] = script;
199                                }
200
201                                //if (streamSubmesh(of, node, mtlName))
202                                if (streamSubmesh(of, obj, mtlName))
203                                        m_submeshNames.push(std::string(node->GetName()));
204
205                                node->ReleaseIGameObject();
206                                nodeIdx++;
207
208                                if (m_config.getExportMultipleFiles() || nodeIdx == nodeCount) {
209
210                                        // write end of this file's XML
211                                        streamFileFooter(of);
212
213                                        // insert new filename --> stream pair into output map
214                                        output[fileName] = std::string(of.str());
215                                        of.str("");
216
217                                        if (nodeIdx != nodeCount) {
218                                                fileName = m_config.getExportPath() + "\\";
219                                                node = m_pGame->GetTopLevelNode(nodeIdx);
220                                                fileName += node->GetName();
221                                                fileName += ".mesh.xml";
222
223                                                // start over again with new data
224                                                streamFileHeader(of);
225                                        }
226                                }
227                        }
228
229                        m_pGame->ReleaseIGame();
230
231                        // export materials if we are writing those
232                        if (m_config.getExportMaterial()) {
233
234                                std::ofstream materialFile;
235                                materialFile.open((m_config.getExportPath() + "\\" + m_config.getMaterialFilename()).c_str(), std::ios::out);
236
237                                if (materialFile.is_open()) {
238                                        for (std::map<std::string, std::string>::iterator it = materialScripts.begin();
239                                                it != materialScripts.end(); ++it)
240                                        {
241                                                materialFile << it->second;
242                                        }
243
244                                        materialFile.close();
245                                }
246                        }
247
248                        return true;
249                }
250                catch (...) {
251                        MessageBox(GetActiveWindow(), "An unexpected error has occurred while trying to export, aborting", "Error", MB_ICONEXCLAMATION);
252
253                        if (m_pGame)
254                                m_pGame->ReleaseIGame();
255
256                        return false;
257                }
258        }
259
260        bool MeshXMLExporter::streamFileHeader(std::ostream &of) {
261
262                // write the XML header tags
263                of << "<?xml version=\"1.0\"?>" << std::endl;
264                of << "<mesh>" << std::endl;
265
266                // *************** Export Submeshes ***************
267                of << "\t<submeshes>" << std::endl;
268
269                of.precision(6);
270                of << std::fixed;
271
272                return true;
273        }
274
275        bool MeshXMLExporter::streamFileFooter(std::ostream &of) {
276
277                of << "\t</submeshes>" << std::endl;
278                // *************** End Submeshes Export ***********
279
280                // if there is a skeleton involved, link that filename here
281                if (m_createSkeletonLink) {
282                        std::string skeletonFilename(m_skeletonFilename);
283                        skeletonFilename = skeletonFilename.substr(0, skeletonFilename.find(".xml"));
284
285                        of << "\t<skeletonlink name=\"" << skeletonFilename << "\" />" << std::endl;
286                }
287
288
289                // *************** Export Submesh Names ***************
290                of << "\t<submeshnames>" << std::endl;
291
292                int idx = 0;
293                while (!m_submeshNames.empty()) {
294                        of << "\t\t<submeshname name=\"" << m_submeshNames.front() << "\" index=\"" << idx << "\" />" << std::endl;
295                        idx++;
296                        m_submeshNames.pop();
297                }
298
299                of << "\t</submeshnames>" << std::endl;
300                // *************** End Submesh Names Export ***********
301
302                of << "</mesh>" << std::endl;
303
304                return true;
305        }
306
307        //bool MeshXMLExporter::streamSubmesh(std::ostream &of, IGameNode *node, std::string &mtlName) {
308        bool MeshXMLExporter::streamSubmesh(std::ostream &of, IGameObject *obj, std::string &mtlName) {
309               
310                //IGameObject* obj = node->GetIGameObject();
311                if (obj->GetIGameType() != IGameMesh::IGAME_MESH)
312                        return false;
313
314                // InitializeData() is important -- it performs all of the WSM/time eval for us; no face data without it
315//              obj->InitializeData();
316                IGameMesh* mesh = (IGameMesh*) obj;
317                int vertCount = mesh->GetNumberOfVerts();
318                int faceCount = mesh->GetNumberOfFaces();
319
320                Tab<int> matIds = mesh->GetActiveMatIDs();
321                Tab<DWORD> smGrpIds = mesh->GetActiveSmgrps();
322                Tab<int> texMaps = mesh->GetActiveMapChannelNum();
323
324                of << "\t\t<submesh ";
325               
326                if (mtlName.length() > 0)
327                        of << "material=\"" << mtlName << "\" ";
328
329                of << "usesharedvertices=\"false\" use32bitindexes=\"";
330                of << (vertCount > 65535);
331                of << "\">" << std::endl;
332
333                // *************** Export Face List ***************
334                of << "\t\t\t<faces count=\"" << faceCount << "\">" << std::endl;
335
336                //std::vector<UVVert
337
338                // iterate the face list, putting vertices in the list for this submesh
339                VertexList vertexList;
340
341                for (int i=0; i<faceCount; i++) {
342
343                        of << "\t\t\t\t<face";
344                        FaceEx* face = mesh->GetFace(i);
345
346                        // do this for each vertex on the face
347                        for (int vi=0; vi<3; vi++) {
348                                Point3 p = mesh->GetVertex(face->vert[vi]);
349
350                                Vertex v(p.x, p.y, p.z);
351
352                                if (m_config.getExportVertexColours()) {
353                                        Point3 c = mesh->GetColorVertex(face->vert[vi]);
354                                        float a = mesh->GetAlphaVertex(face->vert[vi]);
355
356                                        v.setColour(c.x, c.y, c.z, a);
357                                }
358
359                                Point3 n = mesh->GetNormal(face, vi);
360                                v.setNormal(n.x, n.y, n.z);
361
362                                // get each set of texcoords for this vertex
363                                for (int ch=0; ch < texMaps.Count(); ch++) {
364
365                                        Point3 tv;
366                                        DWORD indices[3];
367
368                                        if (mesh->GetMapFaceIndex(texMaps[ch], i, indices))
369                                                tv = mesh->GetMapVertex(texMaps[ch], indices[vi]);
370                                        else
371                                                tv = mesh->GetMapVertex(texMaps[ch], face->vert[vi]);
372
373                                        v.addTexCoord(texMaps[ch], tv.x, tv.y, tv.z);
374                                }
375
376                                int actualVertexIndex = vertexList.add(v);
377
378                                of << " v" << vi + 1 << "=\"" << actualVertexIndex << "\"";
379                        }
380 
381                        of << " />" << std::endl;
382                }
383
384                of << "\t\t\t</faces>" << std::endl;
385                // *************** End Export Face List ***************
386
387
388                // *************** Export Geometry ***************
389                of << "\t\t\t<geometry vertexcount=\"" << vertexList.size() << "\">" << std::endl;
390
391                // *************** Export Vertex Buffer ***************
392                bool exportNormals = true;
393
394                of << std::boolalpha;
395                of << "\t\t\t\t<vertexbuffer positions=\"true\" normals=\"" << exportNormals << "\" colours_diffuse=\"" << m_config.getExportVertexColours() << "\" texture_coords=\"" << texMaps.Count() << "\"";
396               
397                for (i=0; i<texMaps.Count(); i++)
398                        of << " texture_coords_dimensions_" << i << "=\"2\"";
399               
400                of << ">" << std::endl;
401
402                int numVerts = vertexList.size();
403                for (i=0; i < numVerts; i++) {
404
405                        const Vertex& v = vertexList.front();
406
407                        of << "\t\t\t\t\t<vertex>" << std::endl;
408                        of << std::showpoint;
409
410                        const Ogre::Vector3& p = v.getPosition();
411                        float x = p.x;
412                        float y = p.y;
413                        float z = p.z;
414
415                        of << "\t\t\t\t\t\t<position x=\"" << x << "\" y=\"" << y << "\" z=\"" << z << "\" />" << std::endl;
416
417                        if (m_config.getExportVertexColours()) {
418
419                                float r = v.getColour().r;
420                                float g = v.getColour().g;
421                                float b = v.getColour().b;
422
423                                of << "\t\t\t\t\t\t<colour_diffuse value=\"\t" << r << "\t" << g << "\t" << b << "\" />" << std::endl;
424                        }
425
426                        if (exportNormals) {
427
428                                const Ogre::Vector3& n = v.getNormal();
429                                float x = n.x;
430                                float y = n.y;
431                                float z = n.z;
432
433                                of << "\t\t\t\t\t\t<normal x=\"" << x << "\" y=\"" << y << "\" z=\"" << z << "\" />" << std::endl;
434                        }
435
436                        // output the tex coords for each map used
437                        for (int ti=0; ti<texMaps.Count(); ti++) {
438                                int texMap = texMaps[ti];
439
440                                const Ogre::Vector3& uvw = v.getUVW(texMap); 
441
442                                switch (m_config.getTexCoord2D()) {
443                                        case OgreMax::UV:
444                                                of << "\t\t\t\t\t\t<texcoord u=\"" << uvw.x << "\" v=\"" << (1.0 - uvw.y) << "\" />" << std::endl; 
445                                                break;
446                                        case OgreMax::VW:
447                                                of << "\t\t\t\t\t\t<texcoord v=\"" << uvw.y << "\" w=\"" << (1.0 - uvw.z) << "\" />" << std::endl; 
448                                                break;
449                                        case OgreMax::WU:
450                                                of << "\t\t\t\t\t\t<texcoord w=\"" << uvw.z << "\" u=\"" << (1.0 - uvw.x) << "\" />" << std::endl; 
451                                                break;
452                                }
453                        }
454                       
455                        of << std::noshowpoint;
456                        of << "\t\t\t\t\t</vertex>" << std::endl;
457                        vertexList.pop();
458                }
459
460                of << "\t\t\t\t</vertexbuffer>" << std::endl;
461                // *************** End Export Vertex Buffer ***************
462
463                of << "\t\t\t</geometry>" << std::endl;
464                // *************** End Export Geometry ***********
465
466                of << "\t\t</submesh>" << std::endl;
467
468                // this skin extraction code based on an article found here:
469                // http://www.cfxweb.net/modules.php?name=News&file=article&sid=1029
470/*              Object *oRef = node->GetObjectRef();
471
472                if (oRef->SuperClassID() == GEN_DERIVOB_CLASS_ID) {
473                        IDerivedObject *dObj = (IDerivedObject *)oRef;
474                        Modifier *oMod = dObj->GetModifier(0);
475
476                        if (oMod->ClassID() == SKIN_CLASSID) {
477
478                                // flag the export of a skeleton link element
479                                m_createSkeletonLink = true;
480
481                                // stream the boneassignments element
482                                streamBoneAssignments(of, oMod, node);
483                        }
484                }
485
486                of << "\t\t</submesh>" << std::endl;
487
488                if (obj != tri)
489                        delete tri;
490*/
491//              node->ReleaseIGameObject();
492                return true;
493        }
494
495        //bool MeshXMLExporter::streamBoneAssignments(std::ostream &of, Modifier *oMod, INode *node) {
496        bool MeshXMLExporter::streamBoneAssignments(std::ostream &of, Modifier *oMod, IGameNode *node) {
497
498                // wrangle a pointer to the skinning data
499/*              ISkin *skin = (ISkin *) oMod->GetInterface(I_SKIN);
500                ISkinContextData *skinData = skin->GetContextInterface(node);
501
502                // loop through all the vertices, writing out skinning data as we go
503                int skinnedVertexCount = skinData->GetNumPoints();
504
505                if (skinnedVertexCount > 0) {
506
507                        of << "\t\t\t<boneassignments>" << std::endl;
508
509                        int i;
510                        for(i=0; i<skinnedVertexCount; i++) {
511
512                                // grab the bone indices for this vertex
513                                int vertexBoneInfluences = skinData->GetNumAssignedBones(i);
514
515                                if (vertexBoneInfluences > 0) {
516
517                                        int j;
518                                        for (j=0; j < vertexBoneInfluences; j++) {
519
520                                                // get weight per bone influence -- Ogre will ignore bones above
521                                                // 4 and sum the weights to make it work, so leverage that feature
522                                                int boneIdx = getBoneIndex(skin->GetBoneName(skinData->GetAssignedBone(i, j)));
523                                                float vertexWeight = skinData->GetBoneWeight(i, j);
524
525                                                of << "\t\t\t\t<vertexboneassignment vertexindex=\"" << i << "\" boneindex=\"" << boneIdx << "\" weight=\"" << vertexWeight << "\" />" << std::endl;
526                                        }
527                                }
528                        }
529               
530                        of << "\t\t\t</boneassignments>" << std::endl;
531                }
532*/
533                return true;
534        }
535
536        int MeshXMLExporter::getBoneIndex(char *boneName) {
537
538                std::map< std::string, int >::const_iterator it = m_boneIndexMap.find(std::string(boneName));
539                if (it == m_boneIndexMap.end()) {
540                        m_boneIndexMap.insert(std::map< std::string, int >::value_type(std::string(boneName), m_currentBoneIndex));
541                        return m_currentBoneIndex++;
542                }
543                else
544                        return it->second;
545        }
546
547#if 0
548        bool MeshXMLExporter::export(OutputMap& output) {
549
550                try {
551
552                        // all options have been set when actions were taken, so we can just start exporting stuff here
553
554                        // write XML to a strstream
555                        std::stringstream of;
556                        bool rtn = true;
557
558                        // clear the node list and submesh name list
559                        m_nodeList.clear();
560                        while (!m_submeshNames.empty())
561                                m_submeshNames.pop();
562
563                        // populate the node list
564                        m_ei->theScene->EnumTree(this);
565
566                        // check to see if there's anything to export
567                        if (m_nodeList.size() == 0) {
568                                MessageBox(GetActiveWindow(), "No nodes available to export, aborting...", "Nothing To Export", MB_ICONINFORMATION);
569                                return false;
570                        }
571
572                        // if we are writing everything to one file, use the name provided when the user first started the export;
573                        // otherwise, create filenames on the basis of the node (submesh) names
574                        std::string fileName;
575                        if (!m_config.getExportMultipleFiles())
576                                fileName = m_config.getExportFilename();
577                        else {
578                                fileName = m_config.getExportPath() + "\\";
579                                INode *n = *(m_nodeList.begin());
580                                fileName += n->GetName();
581                                fileName += ".mesh.xml";
582                        }
583
584                        // write start of XML data
585                        streamFileHeader(of);
586
587                        std::list<INode *>::iterator it = m_nodeList.begin();
588
589                        // user request -- if no material is assigned to this node, then use an export-specified
590                        // default material name
591                        Mtl *nodeMtl = (*it)->GetMtl();
592                        if (nodeMtl == NULL) {
593                                m_materialMap[m_config.getDefaultMaterialName()] = 0; // we can do this as often as we like -- it will just overwrite zero with zero
594                        }
595
596                        while (it != m_nodeList.end()) {
597
598                                // we already filtered out nodes that had NULL materials, and those that could
599                                // not be converted to TriObjects, so now we know everything we have is good
600
601                                INode *node = *it;
602                                std::string mtlName;
603                               
604                                Mtl *mtl = node->GetMtl();
605                                if (mtl == NULL)
606                                        mtlName = m_config.getDefaultMaterialName();
607                                else
608                                        mtlName = mtl->GetName();
609
610                                // map a material name to its Mtl pointer so that we can retrieve these later
611                                std::string::size_type pos;
612
613                                // clean out any spaces the user left in their material name
614                                while ((pos = mtlName.find_first_of(' ')) != std::string::npos)
615                                        mtlName.replace(pos, 1, _T("_"));
616
617                                m_materialMap[mtlName] = mtl;
618
619                                if (streamSubmesh(of, node, mtlName))
620                                        m_submeshNames.push(std::string((*it)->GetName()));
621
622                                it++;
623
624                                // if we are doing one mesh per file, then close this one and open a new one
625                                if (m_config.getExportMultipleFiles() || it == m_nodeList.end()) {
626
627                                        // write end of this file's XML
628                                        streamFileFooter(of);
629
630                                        // insert new filename --> stream pair into output map
631                                        output[fileName] = std::string(of.str());
632                                        of.str("");
633
634                                        if (it != m_nodeList.end()) {
635                                                fileName = m_config.getExportPath() + "\\";
636                                                INode *n = *it;
637                                                fileName += n->GetName();
638                                                fileName += ".mesh.xml";
639
640                                                // start over again with new data
641                                                streamFileHeader(of);
642                                        }
643                                }
644                        }
645
646                        return rtn;
647                }
648                catch (...) {
649                        MessageBox(GetActiveWindow(), "An unexpected error has occurred while trying to export, aborting", "Error", MB_ICONEXCLAMATION);
650                        return false;
651                }
652        }
653
654        bool MeshXMLExporter::streamFileHeader(std::ostream &of) {
655
656                // write the XML header tags
657                of << "<?xml version=\"1.0\"?>" << std::endl;
658                of << "<mesh>" << std::endl;
659
660                // *************** Export Submeshes ***************
661                of << "\t<submeshes>" << std::endl;
662
663                of.precision(6);
664                of << std::fixed;
665
666                return true;
667        }
668
669        bool MeshXMLExporter::streamFileFooter(std::ostream &of) {
670
671                of << "\t</submeshes>" << std::endl;
672                // *************** End Submeshes Export ***********
673
674                // if there is a skeleton involved, link that filename here
675                if (m_createSkeletonLink) {
676                        std::string skeletonFilename(m_skeletonFilename);
677                        skeletonFilename = skeletonFilename.substr(0, skeletonFilename.find(".xml"));
678
679                        of << "\t<skeletonlink name=\"" << skeletonFilename << "\" />" << std::endl;
680                }
681
682
683                // *************** Export Submesh Names ***************
684                of << "\t<submeshnames>" << std::endl;
685
686                int idx = 0;
687                while (!m_submeshNames.empty()) {
688                        of << "\t\t<submeshname name=\"" << m_submeshNames.front() << "\" index=\"" << idx << "\" />" << std::endl;
689                        idx++;
690                        m_submeshNames.pop();
691                }
692
693                of << "\t</submeshnames>" << std::endl;
694                // *************** End Submesh Names Export ***********
695
696                of << "</mesh>" << std::endl;
697
698                return true;
699        }
700
701        bool MeshXMLExporter::streamSubmesh(std::ostream &of, INode *node, std::string &mtlName) {
702               
703                Object *obj = node->EvalWorldState(m_i->GetTime()).obj;
704                TriObject *tri = (TriObject *) obj->ConvertToType(m_i->GetTime(), Class_ID(TRIOBJ_CLASS_ID, 0));
705
706                int i;
707                Mesh mesh = tri->GetMesh();
708                Mtl* mtl = node->GetMtl();
709                Matrix3 ptm = node->GetObjTMAfterWSM(m_i->GetTime());
710
711                int vertCount = mesh.getNumVerts();
712                int faceCount = mesh.getNumFaces();
713
714                of << "\t\t<submesh ";
715               
716                if (mtlName.length() > 0)
717                        of << "material=\"" << mtlName << "\" ";
718
719                of << "usesharedvertices=\"false\" use32bitindexes=\"";
720                of << (vertCount > 65535);
721                of << "\">" << std::endl;
722
723                // *************** Export Face List ***************
724                of << "\t\t\t<faces count=\"" << faceCount << "\">" << std::endl;
725
726                // store UV coords from the faces, not from the vertices themselves
727                std::vector<UVVert> texCoords;
728                texCoords.reserve(vertCount);
729
730                for (i=0; i<faceCount; i++) {
731                        int v1 = mesh.faces[i].v[0];
732                        int v2 = mesh.faces[i].v[1];
733                        int v3 = mesh.faces[i].v[2];
734
735                        UVVert uv;
736                        uv.x = mesh.tvFace[i].t[0];
737                        uv.y = mesh.tvFace[i].t[1];
738                        uv.z = mesh.tvFace[i].t[2];
739
740                        if (m_config.getInvertNormals()) {
741                                int tmp = v2;
742                                v2 = v3;
743                                v3 = tmp;
744                        }
745
746                        of << "\t\t\t\t<face v1=\"" << v1 << "\" v2=\"" << v2 << "\" v3=\"" << v3 << "\" />" << std::endl;
747                }
748
749                of << "\t\t\t</faces>" << std::endl;
750                // *************** End Export Face List ***************
751
752
753                // *************** Export Geometry ***************
754                of << "\t\t\t<geometry vertexcount=\"" << vertCount << "\">" << std::endl;
755
756                // *************** Export Vertex Buffer ***************
757                if (m_config.getRebuildNormals()) {
758                        mesh.buildNormals();
759                }
760
761                bool exportNormals = (mesh.normalsBuilt > 0);
762
763                of << std::boolalpha;
764
765                // NB: we don't export tex coords unless we are exporting a material as well
766                // NB: apparently Max cannot just tell us how many texmaps a material uses...so we have to add them up
767
768                // we need a list of enabled map indices for later
769                std::list<unsigned int> texMaps;
770                if (mtl->ClassID() == Class_ID(DMTL_CLASS_ID, 0)) {
771                        StdMat* sMtl = (StdMat*) mtl;
772                        if (m_config.getExportMaterial()) {
773                                for (int t=0; t<sMtl->NumSubTexmaps(); t++)
774               
775                                        if (sMtl->MapEnabled(t)) {
776                                                BitmapTex* TMap = (BitmapTex*)sMtl->GetSubTexmap(ID_DI);
777                                                if (!TMap)
778                                                return false;
779
780                                                //Check if we have a Bitmap Texture material (BitmapTex)
781                                                if (TMap->ClassID() != Class_ID(BMTEX_CLASS_ID,0))
782                                                return false; //Not interesting
783
784                                                UVGen * pUVGen = TMap->GetTheUVGen() ;
785                                                if(!pUVGen)
786                                                return false;
787
788                                                const int iAxis = pUVGen->GetAxis();
789                                                texMaps.push_back(t);
790                                }
791                        }
792                }
793
794                of << "\t\t\t\t<vertexbuffer positions=\"true\" normals=\"" << exportNormals << "\" colours_diffuse=\"" << m_config.getExportVertexColours() << "\" texture_coords=\"" << texMaps.size() << "\"";
795               
796                for (i=0; i<texMaps.size(); i++)
797                        of << " texture_coords_dimensions_" << i << "=\"2\"";
798               
799                of << ">" << std::endl;
800
801                for (i=0; i<vertCount; i++) {
802                        Point3 v = mesh.getVert(i);
803
804                        // transform v into parent's coord system
805                        v = v * ptm;
806
807                        Point3 vc;
808                        vc.x = 0.0f;
809                        vc.y = 0.0f;
810                        vc.z = 0.0f;
811
812                        if (mesh.vertCol != 0) {
813                                vc = mesh.vertCol[i];
814                        }
815
816                        of << "\t\t\t\t\t<vertex>" << std::endl;
817                        of << std::showpoint;
818
819                        float x = v.x;// * m_scale;
820                        float y = v.y;// * m_scale;
821                        float z = v.z;// * m_scale;
822
823                        if (m_config.getInvertYZ()) {
824                                float tmp = y;
825                                y = z;
826                                z = -tmp;
827                        }
828
829                        of << "\t\t\t\t\t\t<position x=\"" << x << "\" y=\"" << y << "\" z=\"" << z << "\" />" << std::endl;
830
831                        if (m_config.getExportVertexColours())
832                                of << "\t\t\t\t\t\t<colour_diffuse value=\"\t" << vc.x << "\t" << vc.y << "\t" << vc.z << "\" />" << std::endl;
833                       
834                        if (exportNormals) {
835        //                      Point3 n = mesh.getNormal(i);
836                                RVertex *rv = mesh.getRVertPtr(i);
837                                Point3 n = rv->rn.getNormal();
838                                        n = n.Normalize();
839
840                                float x = n.x;
841                                float y = n.y;
842                                float z = n.z;
843
844                                if (m_config.getInvertYZ()) {
845                                        float tmp = y;
846                                        y = z;
847                                        z = -tmp;
848                                }
849                               
850                                if (m_config.getInvertNormals())
851                                        of << "\t\t\t\t\t\t<normal x=\"" << -x << "\" y=\"" << -y << "\" z=\"" << -z << "\" />" << std::endl;
852                                else
853                                        of << "\t\t\t\t\t\t<normal x=\"" << x << "\" y=\"" << y << "\" z=\"" << z << "\" />" << std::endl;
854                        }
855
856                        // output the tex coords for each map used
857                        std::list<unsigned int>::iterator texMap = texMaps.begin();
858                        while (texMap != texMaps.end()) {
859                                UVVert uv;
860                               
861                                if (*texMap <= 1)
862                                        uv = mesh.tVerts[i];
863                                else
864                                        uv = mesh.mapVerts(*texMap)[i];
865
866                                switch (m_config.getTexCoord2D()) {
867                                        case OgreMax::UV:
868                                                of << "\t\t\t\t\t\t<texcoord u=\"" << uv.x << "\" v=\"" << (1.0 - uv.y) << "\" />" << std::endl;
869                                                break;
870                                        case OgreMax::VW:
871                                                of << "\t\t\t\t\t\t<texcoord v=\"" << uv.y << "\" w=\"" << (1.0 - uv.z) << "\" />" << std::endl;
872                                                break;
873                                        case OgreMax::WU:
874                                                of << "\t\t\t\t\t\t<texcoord w=\"" << uv.z << "\" u=\"" << (1.0 - uv.x) << "\" />" << std::endl;
875                                                break;
876                                }
877
878                                texMap++;
879                        }
880                       
881                        of << std::noshowpoint;
882                        of << "\t\t\t\t\t</vertex>" << std::endl;
883                }
884
885                of << "\t\t\t\t</vertexbuffer>" << std::endl;
886                // *************** End Export Vertex Buffer ***************
887
888                of << "\t\t\t</geometry>" << std::endl;
889                // *************** End Export Geometry ***********
890
891                // this skin extraction code based on an article found here:
892                // http://www.cfxweb.net/modules.php?name=News&file=article&sid=1029
893                Object *oRef = node->GetObjectRef();
894
895                if (oRef->SuperClassID() == GEN_DERIVOB_CLASS_ID) {
896                        IDerivedObject *dObj = (IDerivedObject *)oRef;
897                        Modifier *oMod = dObj->GetModifier(0);
898
899                        if (oMod->ClassID() == SKIN_CLASSID) {
900
901                                // flag the export of a skeleton link element
902                                m_createSkeletonLink = true;
903
904                                // stream the boneassignments element
905                                streamBoneAssignments(of, oMod, node);
906                        }
907                }
908
909                of << "\t\t</submesh>" << std::endl;
910
911                if (obj != tri)
912                        delete tri;
913
914                return true;
915        }
916
917        bool MeshXMLExporter::streamBoneAssignments(std::ostream &of, Modifier *oMod, INode *node) {
918               
919
920                // wrangle a pointer to the skinning data
921                ISkin *skin = (ISkin *) oMod->GetInterface(I_SKIN);
922                ISkinContextData *skinData = skin->GetContextInterface(node);
923
924                // loop through all the vertices, writing out skinning data as we go
925                int skinnedVertexCount = skinData->GetNumPoints();
926
927                if (skinnedVertexCount > 0) {
928
929                        of << "\t\t\t<boneassignments>" << std::endl;
930
931                        int i;
932                        for(i=0; i<skinnedVertexCount; i++) {
933
934                                // grab the bone indices for this vertex
935                                int vertexBoneInfluences = skinData->GetNumAssignedBones(i);
936
937                                if (vertexBoneInfluences > 0) {
938
939                                        int j;
940                                        for (j=0; j < vertexBoneInfluences; j++) {
941
942                                                // get weight per bone influence -- Ogre will ignore bones above
943                                                // 4 and sum the weights to make it work, so leverage that feature
944                                                int boneIdx = getBoneIndex(skin->GetBoneName(skinData->GetAssignedBone(i, j)));
945                                                float vertexWeight = skinData->GetBoneWeight(i, j);
946
947                                                of << "\t\t\t\t<vertexboneassignment vertexindex=\"" << i << "\" boneindex=\"" << boneIdx << "\" weight=\"" << vertexWeight << "\" />" << std::endl;
948                                        }
949                                }
950                        }
951               
952                        of << "\t\t\t</boneassignments>" << std::endl;
953                }
954
955                return true;
956        }
957
958        int MeshXMLExporter::getBoneIndex(char *boneName) {
959
960                std::map< std::string, int >::const_iterator it = m_boneIndexMap.find(std::string(boneName));
961                if (it == m_boneIndexMap.end()) {
962                        m_boneIndexMap.insert(std::map< std::string, int >::value_type(std::string(boneName), m_currentBoneIndex));
963                        return m_currentBoneIndex++;
964                }
965                else
966                        return it->second;
967        }
968
969        // pulled directly from the Sparks site:
970        // http://sparks.discreet.com/Knowledgebase/sdkdocs_v8/prog/cs/cs_physique_export.html
971        // Also available in the SDK docs. Used to find out if this node has a physique modifier or not.
972        // If it does, it returns a pointer to the modifier, and if not, returns NULL. This can be used to
973        // determine whether a node is bone or mesh -- mesh nodes will have Physique modifiers, bone nodes
974        // will not.
975        Modifier* MeshXMLExporter::FindPhysiqueModifier (INode* nodePtr)
976        {
977                // Get object from node. Abort if no object.
978                Object* ObjectPtr = nodePtr->GetObjectRef();
979
980                if (!ObjectPtr) return NULL;
981
982                // Is derived object ?
983                while (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID && ObjectPtr)
984                {
985                        // Yes -> Cast.
986                        IDerivedObject *DerivedObjectPtr = (IDerivedObject *)(ObjectPtr);
987                                                       
988                        // Iterate over all entries of the modifier stack.
989                        int ModStackIndex = 0;
990                        while (ModStackIndex < DerivedObjectPtr->NumModifiers())
991                        {
992                                // Get current modifier.
993                                Modifier* ModifierPtr = DerivedObjectPtr->GetModifier(ModStackIndex);
994
995                                // Is this Physique ?
996                                if (ModifierPtr->ClassID() == Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B))
997                                {
998                                        // Yes -> Exit.
999                                        return ModifierPtr;
1000                                }
1001
1002                                // Next modifier stack entry.
1003                                ModStackIndex++;
1004                        }
1005                        ObjectPtr = DerivedObjectPtr->GetObjRef();
1006                }
1007
1008                // Not found.
1009                return NULL;
1010        }
1011#endif
1012
1013}
1014
Note: See TracBrowser for help on using the repository browser.