Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/Tools/MayaExport/src/submesh.cpp @ 6

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

=…

File size: 15.5 KB
Line 
1////////////////////////////////////////////////////////////////////////////////
2// submesh.cpp
3// Author     : Francesco Giordana
4// Start Date : January 13, 2005
5// Copyright  : (C) 2006 by Francesco Giordana
6// Email      : fra.giordana@tiscali.it
7////////////////////////////////////////////////////////////////////////////////
8
9/*********************************************************************************
10*                                                                                *
11*   This program is free software; you can redistribute it and/or modify         *
12*   it under the terms of the GNU Lesser General Public License as published by  *
13*   the Free Software Foundation; either version 2 of the License, or            *
14*   (at your option) any later version.                                          *
15*                                                                                *
16**********************************************************************************/
17
18#include "submesh.h"
19
20namespace OgreMayaExporter
21{
22        /***** Class Submesh *****/
23        // constructor
24        Submesh::Submesh(const MString& name)
25        {
26                m_pBlendShape = NULL;
27                clear();
28                m_name = name;
29        }
30
31        // destructor
32        Submesh::~Submesh()
33        {
34                clear();
35        }
36
37        // clear data
38        void Submesh::clear()
39        {
40                m_name = "";
41                m_numTriangles = 0;
42                m_pMaterial = NULL;
43                m_vertices.clear();
44                m_faces.clear();
45                m_uvsets.clear();
46                m_use32bitIndexes = false;
47                if (m_pBlendShape)
48                        delete m_pBlendShape;
49                m_pBlendShape = NULL;
50        }
51
52        // return number of triangles composing the mesh
53        long Submesh::numTriangles()
54        {
55                return m_numTriangles;
56        }
57
58        // return number of vertices composing the mesh
59        long Submesh::numVertices()
60        {
61                return m_numVertices;
62        }
63
64        // return submesh name
65        MString& Submesh::name()
66        {
67                return m_name;
68        }
69
70/***** load data *****/
71        MStatus Submesh::loadMaterial(MObject& shader,MStringArray& uvsets,ParamList& params)
72        {
73                int i;
74                MPlug plug;
75                MPlugArray srcplugarray;
76                bool foundShader = false;
77                MStatus stat;
78                MFnDependencyNode* pShader;
79                //get shader from shading group
80                MFnDependencyNode shadingGroup(shader);
81                plug = shadingGroup.findPlug("surfaceShader");
82                plug.connectedTo(srcplugarray,true,false,&stat);
83                for (i=0; i<srcplugarray.length() && !foundShader; i++)
84                {
85                        if (srcplugarray[i].node().hasFn(MFn::kLambert) || srcplugarray[i].node().hasFn(MFn::kSurfaceShader) || 
86                                srcplugarray[i].node().hasFn(MFn::kPluginHwShaderNode) )
87                        {
88                                pShader = new MFnDependencyNode(srcplugarray[i].node());
89                                foundShader = true;
90                        }
91                }
92                if (foundShader)
93                {
94                        std::cout << "Found material: " << pShader->name().asChar() << "\n";
95                        std::cout.flush();
96                        //check if this material has already been created
97                        //fix material name, adding the requested prefix
98                        MString tmpStr = params.matPrefix;
99                        if (tmpStr != "")
100                                tmpStr += "/";
101                        tmpStr += pShader->name();
102                        MStringArray tmpStrArray;
103                        tmpStr.split(':',tmpStrArray);
104                        MString name = "";
105                        for (i=0; i<tmpStrArray.length(); i++)
106                        {
107                                name += tmpStrArray[i];
108                                if (i < tmpStrArray.length()-1)
109                                        name += "_";
110                        }
111                        Material* pMaterial = MaterialSet::getSingleton().getMaterial(name);
112                        //if the material has already been created, update the pointer
113                        if (pMaterial)
114                                m_pMaterial = pMaterial;
115                        //else create it and add it to the material set
116                        else
117                        {
118                                pMaterial = new Material();
119                                pMaterial->load(pShader,uvsets,params);
120                                m_pMaterial = pMaterial;
121                                MaterialSet::getSingleton().addMaterial(pMaterial);
122                        }
123                        //delete temporary shader
124                        delete pShader;
125                }
126                else
127                {
128                        std::cout << "Unsupported material, replacing with default lambert\n";
129                        std::cout.flush();
130                        m_pMaterial = MaterialSet::getSingleton().getDefaultMaterial();
131                }
132               
133                //loading complete
134                return MS::kSuccess;
135        }
136
137        MStatus Submesh::load(const MDagPath& dag,std::vector<face>& faces, std::vector<vertexInfo>& vertInfo, MPointArray& points, 
138                MFloatVectorArray& normals, MStringArray& texcoordsets,ParamList& params,bool opposite)
139        {
140                //save the dag path of the maya node from which this submesh will be created
141                m_dagPath = dag;
142                //create the mesh Fn
143                MFnMesh mesh(dag);
144                int i,j,k;
145                std::cout << "Loading submesh associated to material: " << m_pMaterial->name().asChar() << "...";
146                std::cout.flush();
147                //save uvsets info
148                for (i=m_uvsets.size(); i<texcoordsets.length(); i++)
149                {
150                        uvset uv;
151                        uv.size = 2;
152                        m_uvsets.push_back(uv);
153                }
154                //iterate over faces array, to retrieve vertices info
155                for (i=0; i<faces.size(); i++)
156                {
157                        face newFace;
158                        // if we are using shared geometry, indexes refer to the vertex buffer of the whole mesh
159                        if (params.useSharedGeom)
160                        {
161                                if(opposite)
162                                {       // reverse order of face vertices for correct culling
163                                        newFace.v[0] = faces[i].v[2];
164                                        newFace.v[1] = faces[i].v[1];
165                                        newFace.v[2] = faces[i].v[0];
166                                }
167                                else
168                                {
169                                        newFace.v[0] = faces[i].v[0];
170                                        newFace.v[1] = faces[i].v[1];
171                                        newFace.v[2] = faces[i].v[2];
172                                }
173                        }
174                        // otherwise we create a vertex buffer for this submesh
175                        else
176                        {       // faces are triangles, so retrieve index of the three vertices
177                                for (j=0; j<3; j++)
178                                {
179                                        vertex v;
180                                        vertexInfo vInfo = vertInfo[faces[i].v[j]];
181                                        // save vertex coordinates (rescale to desired length unit)
182                                        MPoint point = points[vInfo.pointIdx] * params.lum;
183                                        if (fabs(point.x) < PRECISION)
184                                                point.x = 0;
185                                        if (fabs(point.y) < PRECISION)
186                                                point.y = 0;
187                                        if (fabs(point.z) < PRECISION)
188                                                point.z = 0;
189                                        v.x = point.x;
190                                        v.y = point.y;
191                                        v.z = point.z;
192                                        // save vertex normal
193                                        MFloatVector normal = normals[vInfo.normalIdx];
194                                        if (fabs(normal.x) < PRECISION)
195                                                normal.x = 0;
196                                        if (fabs(normal.y) < PRECISION)
197                                                normal.y = 0;
198                                        if (fabs(normal.z) < PRECISION)
199                                                normal.z = 0;
200                                        if (opposite)
201                                        {
202                                                v.n.x = -normal.x;
203                                                v.n.y = -normal.y;
204                                                v.n.z = -normal.z;
205                                        }
206                                        else
207                                        {
208                                                v.n.x = normal.x;
209                                                v.n.y = normal.y;
210                                                v.n.z = normal.z;
211                                        }
212                                        v.n.normalize();
213                                        // save vertex color
214                                        v.r = vInfo.r;
215                                        v.g = vInfo.g;
216                                        v.b = vInfo.b;
217                                        v.a = vInfo.a;
218                                        // save vertex bone assignements
219                                        for (k=0; k<vInfo.vba.size(); k++)
220                                        {
221                                                vba newVba;
222                                                newVba.jointIdx = vInfo.jointIds[k];
223                                                newVba.weight = vInfo.vba[k];
224                                                v.vbas.push_back(newVba);
225                                        }
226                                        // save texture coordinates
227                                        for (k=0; k<vInfo.u.size(); k++)
228                                        {
229                                                texcoords newTexCoords;
230                                                newTexCoords.u = vInfo.u[k];
231                                                newTexCoords.v = vInfo.v[k];
232                                                newTexCoords.w = 0;
233                                                v.texcoords.push_back(newTexCoords);
234                                        }
235                                        // save vertex index in maya mesh, to retrieve future positions of the same vertex
236                                        v.index = vInfo.pointIdx;
237                                        // add newly created vertex to vertex list
238                                        m_vertices.push_back(v);
239                                        if (opposite)   // reverse order of face vertices to get correct culling
240                                                newFace.v[2-j] = m_vertices.size() - 1;
241                                        else
242                                                newFace.v[j] = m_vertices.size() - 1;
243                                }
244                        }
245                        m_faces.push_back(newFace);
246                }
247                // set use32bitIndexes flag
248                if (params.useSharedGeom || (m_vertices.size() > 65535) || (m_faces.size() > 65535))
249                        m_use32bitIndexes = true;
250                else
251                        m_use32bitIndexes = false;
252                // get submesh bounding box
253                MPoint min = mesh.boundingBox().min();
254                MPoint max = mesh.boundingBox().max();
255                MBoundingBox bbox(min,max);
256                if (params.exportWorldCoords)
257                        bbox.transformUsing(dag.inclusiveMatrix());
258                min = bbox.min() * params.lum;
259                max = bbox.max() * params.lum;
260                MBoundingBox newbbox(min,max);
261                m_boundingBox = newbbox;
262                // add submesh pointer to parameters list
263                params.loadedSubmeshes.push_back(this);
264
265                std::cout << "DONE\n";
266                std::cout.flush();
267                return MS::kSuccess;
268        }
269
270
271        // Load a keyframe for this submesh
272        MStatus Submesh::loadKeyframe(Track& t,float time,ParamList& params)
273        {
274                int i;
275                // create a new keyframe
276                vertexKeyframe k;
277                // set keyframe time
278                k.time = time;
279                // get the mesh Fn
280                MFnMesh mesh(m_dagPath);
281                // get vertex positions
282                MFloatPointArray points;
283                if (params.exportWorldCoords)
284                        mesh.getPoints(points,MSpace::kWorld);
285                else
286                        mesh.getPoints(points,MSpace::kObject);
287                // calculate vertex offsets
288                for (i=0; i<m_vertices.size(); i++)
289                {
290                        vertexPosition pos;
291                        vertex v = m_vertices[i];
292                        pos.x = points[v.index].x * params.lum;
293                        pos.y = points[v.index].y * params.lum;
294                        pos.z = points[v.index].z * params.lum;
295                        if (fabs(pos.x) < PRECISION)
296                                        pos.x = 0;
297                        if (fabs(pos.y) < PRECISION)
298                                pos.y = 0;
299                        if (fabs(pos.z) < PRECISION)
300                                pos.z = 0;
301                        k.positions.push_back(pos);
302                }
303                // add keyframe to given track
304                t.addVertexKeyframe(k);
305                if (params.vertBB)
306                {
307                        // update bounding box
308                        MPoint min = mesh.boundingBox().min();
309                        MPoint max = mesh.boundingBox().max();
310                        MBoundingBox bbox(min,max);
311                        if (params.exportWorldCoords)
312                                bbox.transformUsing(m_dagPath.inclusiveMatrix());
313                        min = bbox.min() * params.lum;
314                        max = bbox.max() * params.lum;
315                        MBoundingBox newbbox(min,max);
316                        m_boundingBox.expand(newbbox);
317                }
318                // keyframe successfully loaded
319                return MS::kSuccess;
320        }
321
322
323
324/***** Export data *****/
325        // Write submesh data to an Ogre compatible mesh
326        MStatus Submesh::createOgreSubmesh(Ogre::MeshPtr pMesh,const ParamList& params)
327        {
328                int i,j;
329                MStatus stat;
330                // Create a new submesh
331                Ogre::SubMesh* pSubmesh;
332                if (m_name != "")
333                        pSubmesh = pMesh->createSubMesh(m_name.asChar());
334                else
335                        pSubmesh = pMesh->createSubMesh();
336                // Set material
337        pSubmesh->setMaterialName(m_pMaterial->name().asChar());
338        // Set use shared geometry flag
339                pSubmesh->useSharedVertices = params.useSharedGeom;
340                // Create vertex data for current submesh
341                pSubmesh->vertexData = new Ogre::VertexData();
342        // Set number of indexes
343        pSubmesh->indexData->indexCount = 3*m_faces.size();
344                pSubmesh->vertexData->vertexCount = m_vertices.size();
345                // Check if we need to use 32 bit indexes
346                bool use32BitIndexes = false;
347                if (m_vertices.size() > 65536 || params.useSharedGeom)
348                {
349                        use32BitIndexes = true;
350                }
351                // Create a new index buffer
352                pSubmesh->indexData->indexBuffer = 
353                        Ogre::HardwareBufferManager::getSingleton().createIndexBuffer(
354                                use32BitIndexes ? Ogre::HardwareIndexBuffer::IT_32BIT : Ogre::HardwareIndexBuffer::IT_16BIT,
355                                pSubmesh->indexData->indexCount,
356                                Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
357                // Fill the index buffer with faces data
358                if (use32BitIndexes)
359        {
360                        Ogre::uint32* pIdx = static_cast<Ogre::uint32*>(
361                                pSubmesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
362                        for (i=0; i<m_faces.size(); i++)
363                        {
364                                *pIdx++ = static_cast<Ogre::uint32>(m_faces[i].v[0]);
365                                *pIdx++ = static_cast<Ogre::uint32>(m_faces[i].v[1]);
366                                *pIdx++ = static_cast<Ogre::uint32>(m_faces[i].v[2]);
367                        }
368                        pSubmesh->indexData->indexBuffer->unlock();
369        }
370        else
371        {
372            Ogre::uint16* pIdx = static_cast<Ogre::uint16*>(
373                                pSubmesh->indexData->indexBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD));
374            for (i=0; i<m_faces.size(); i++)
375                        {
376                                *pIdx++ = static_cast<Ogre::uint16>(m_faces[i].v[0]);
377                                *pIdx++ = static_cast<Ogre::uint16>(m_faces[i].v[1]);
378                                *pIdx++ = static_cast<Ogre::uint16>(m_faces[i].v[2]);
379                        }
380                        pSubmesh->indexData->indexBuffer->unlock();
381                }
382                // Define vertex declaration (only if we're not using shared geometry)
383                if(!params.useSharedGeom)
384                {
385                        Ogre::VertexDeclaration* pDecl = pSubmesh->vertexData->vertexDeclaration;
386                        unsigned buf = 0;
387                        size_t offset = 0;
388                        // Add vertex position
389                        pDecl->addElement(buf, offset, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
390                        offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
391                        // Add vertex normal
392                        if (params.exportVertNorm)
393                        {
394                                pDecl->addElement(buf, offset, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
395                                offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3);
396                        }
397                        // Add vertex colour
398                        if(params.exportVertCol)
399                        {
400                                pDecl->addElement(buf, offset, Ogre::VET_FLOAT4, Ogre::VES_DIFFUSE);
401                                offset += Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT4);
402                        }
403                        // Add texture coordinates
404                        for (i=0; i<m_vertices[0].texcoords.size(); i++)
405                        {
406                                Ogre::VertexElementType uvType = Ogre::VertexElement::multiplyTypeCount(Ogre::VET_FLOAT1, 2);
407                                pDecl->addElement(buf, offset, uvType, Ogre::VES_TEXTURE_COORDINATES, i);
408                                offset += Ogre::VertexElement::getTypeSize(uvType);
409                        }
410                        Ogre::VertexDeclaration* pOptimalDecl = pDecl->getAutoOrganisedDeclaration(
411                                params.exportVBA,params.exportBlendShapes || params.exportVertAnims);
412                        // Fill the vertex buffer using the newly created vertex declaration
413                        stat = createOgreVertexBuffer(pSubmesh,pDecl,m_vertices);
414                        // Write vertex bone assignements list
415                        if (params.exportVBA)
416                        {
417                                // Create a new vertex bone assignements list
418                                Ogre::SubMesh::VertexBoneAssignmentList vbas;
419                                // Scan list of shared geometry vertices
420                                for (i=0; i<m_vertices.size(); i++)
421                                {
422                                        vertex v = m_vertices[i];
423                                        // Add all bone assignemnts for every vertex to the bone assignements list
424                                        for (j=0; j<v.vbas.size(); j++)
425                                        {
426                                                Ogre::VertexBoneAssignment vba;
427                                                vba.vertexIndex = i;
428                                                vba.boneIndex = v.vbas[j].jointIdx;
429                                                vba.weight = v.vbas[j].weight;
430                                                vbas.insert(Ogre::SubMesh::VertexBoneAssignmentList::value_type(i, vba));
431                                        }
432                                }
433                                // Rationalise the bone assignements list
434                                pSubmesh->parent->_rationaliseBoneAssignments(pSubmesh->vertexData->vertexCount,vbas);
435                                // Add bone assignements to the submesh
436                                for (Ogre::SubMesh::VertexBoneAssignmentList::iterator bi = vbas.begin(); bi != vbas.end(); bi++)
437                                {
438                                        pSubmesh->addBoneAssignment(bi->second);
439                                }
440                                pSubmesh->_compileBoneAssignments();
441                        }
442                        pSubmesh->vertexData->reorganiseBuffers(pOptimalDecl);
443                }
444                return MS::kSuccess;
445        }
446
447
448        // Create an Ogre compatible vertex buffer
449        MStatus Submesh::createOgreVertexBuffer(Ogre::SubMesh* pSubmesh,Ogre::VertexDeclaration* pDecl,const std::vector<vertex>& vertices)
450        {
451                Ogre::HardwareVertexBufferSharedPtr vbuf = 
452                        Ogre::HardwareBufferManager::getSingleton().createVertexBuffer(pDecl->getVertexSize(0),
453                        pSubmesh->vertexData->vertexCount, 
454                        Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY);
455                pSubmesh->vertexData->vertexBufferBinding->setBinding(0, vbuf);
456                size_t vertexSize = pDecl->getVertexSize(0);
457                char* pBase = static_cast<char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD));
458                Ogre::VertexDeclaration::VertexElementList elems = pDecl->findElementsBySource(0);
459                Ogre::VertexDeclaration::VertexElementList::iterator ei, eiend;
460                eiend = elems.end();
461                float* pFloat;
462                // Fill the vertex buffer with shared geometry data
463                long vi;
464                Ogre::ColourValue col;
465                float ucoord, vcoord;
466                for (vi=0; vi<vertices.size(); vi++)
467                {
468                        int iTexCoord = 0;
469                        vertex v = vertices[vi];
470                        for (ei = elems.begin(); ei != eiend; ++ei)
471                        {
472                                Ogre::VertexElement& elem = *ei;
473                                switch(elem.getSemantic())
474                                {
475                                case Ogre::VES_POSITION:
476                                        elem.baseVertexPointerToElement(pBase, &pFloat);
477                                        *pFloat++ = v.x;
478                                        *pFloat++ = v.y;
479                                        *pFloat++ = v.z;
480                                        break;
481                                case Ogre::VES_NORMAL:
482                                        elem.baseVertexPointerToElement(pBase, &pFloat);
483                                        *pFloat++ = v.n.x;
484                                        *pFloat++ = v.n.y;
485                                        *pFloat++ = v.n.z;
486                                        break;
487                                case Ogre::VES_DIFFUSE:
488                                        elem.baseVertexPointerToElement(pBase, &pFloat);
489                                        *pFloat++ = v.r;
490                                        *pFloat++ = v.g;
491                                        *pFloat++ = v.b;
492                                        *pFloat++ = v.a;
493                                        break;
494                                case Ogre::VES_TEXTURE_COORDINATES:
495                                        elem.baseVertexPointerToElement(pBase, &pFloat);
496                                        ucoord = v.texcoords[iTexCoord].u;
497                                        vcoord = v.texcoords[iTexCoord].v;
498                                        *pFloat++ = ucoord;
499                                        *pFloat++ = vcoord;
500                                        iTexCoord++;
501                                        break;
502                                }
503                        }
504                        pBase += vertexSize;
505                }
506                vbuf->unlock();
507                return MS::kSuccess;
508        }
509
510}; //end of namespace
Note: See TracBrowser for help on using the repository browser.