source: OGRE/trunk/ogrenew/Tools/VRMLConverter/src/VRML2mesh.cpp @ 657

Revision 657, 15.0 KB checked in by mattausch, 19 years ago (diff)

added ogre dependencies and patched ogre sources

Line 
1#include "stdafx.h"
2
3struct vertex {
4        int pos, tc, normal, colour;
5
6        bool operator<(const vertex &v) const {
7                if (pos < v.pos) return true;
8                if (pos > v.pos) return false;
9                if (normal < v.normal) return true;
10                if (normal > v.normal) return false;
11                if (tc < v.tc) return true;
12                if (tc > v.tc) return false;
13                return colour < v.colour;
14        }
15};
16
17// VRML face
18struct face {
19        std::vector<int> indices;
20};
21
22// OGRE face
23struct triangle {
24        int vertices[3];
25};
26
27typedef std::vector<Vector3> Vec3Vec;
28typedef std::vector<vertex> VertVec;
29typedef std::vector<face> FaceVec;
30typedef std::vector<triangle> TriVec;
31typedef std::vector<int> IntVec;
32typedef std::map<vertex, int> VertMap;
33
34// traverse the scene graph looking for Shapes
35void parseFile(Mesh *, const vrmllib::file &);
36void parseNode(Mesh *, const vrmllib::node *, Matrix4 = Matrix4::IDENTITY);
37
38// generate a SubMesh from a Shape
39void parseShape(Mesh *, const Shape *, Matrix4);
40
41        // helpers:
42        Ogre::MaterialPtr parseMaterial(const Appearance *, const String &name);
43        void parseFaces(FaceVec &, const IndexedFaceSet *);
44        void triangulateAndExpand(TriVec &, VertVec &, const FaceVec &, const Shape *);
45        void copyToSubMesh(SubMesh *, const TriVec &, const VertVec &, const Shape *, const Matrix4 &);
46
47// get the array index for a VRML vertex property
48int getIndex(const IntVec &coordIndex, const IntVec &, bool perVertex, int facenr, int vertnr);
49
50// used by findName*
51typedef std::map<const vrmllib::node *, String> NameMap;
52NameMap gNameMap;
53
54// find name of DEFined node
55const String *findName(const vrmllib::node *n);
56const String *findNameRecursive(const vrmllib::node *n);
57
58String gBaseName; // base name of the input file (no path or extension)
59
60// conversion functions:
61inline Vector3 vec(const vrmllib::vec3 &v) { return Vector3(v.x, v.y, v.z); }
62inline ColourValue col(const vrmllib::col3 &c) { return ColourValue(c.r, c.g, c.b); }
63inline void copyVec(Real *d, const Vector3 &s) { d[0] = s.x; d[1] = s.y; d[2] = s.z; }
64inline void copyVec(Real *d, const vec2 &s) { d[0] = s.x; d[1] = s.y; }
65
66Matrix4 transMat(vrmllib::vec3, bool inverse = false);
67Matrix4 scaleMat(vrmllib::vec3, bool inverse = false);
68Matrix4 rotMat(vrmllib::rot, bool inverse = false);
69
70int main(int argc, char **argv)
71{
72try
73{
74        String inname, outname, path;
75
76        if (argc != 2 && argc != 3)
77                throw
78                        "Wrong number of arguments.\n"
79                        "       Usage: VRML2mesh <input vrml file> [output mesh file]";
80
81        inname = argv[1];
82
83        // get base name
84        gBaseName = inname;
85        size_t p = gBaseName.find_last_of("/\\");
86        if (p != gBaseName.npos) {
87                path.assign(gBaseName, 0, p+1);
88                gBaseName.erase(0, p+1);
89        }
90        p = gBaseName.rfind('.');
91        if (p != gBaseName.npos)
92                gBaseName.erase(p);
93
94        if (argc == 3)
95                outname = argv[2];
96        else
97                outname = path + gBaseName + ".mesh";
98
99        LogManager log;
100        log.createLog(path + "VRML2mesh.log");
101
102        Math math;
103    ResourceGroupManager resGrpMgr;
104        MaterialManager materialMgr;
105        MeshSerializer meshSer;
106
107        Mesh mesh("conversionTarget");
108
109        try {
110                log.logMessage("Reading " + inname);
111
112                // read VRML file
113                std::ifstream infile(inname.c_str());
114                if (!infile.is_open())
115                        throw "failed to open input file";
116
117                vrmllib::file vfile(infile);
118                log.logMessage("Finished parsing VRML file");
119
120                // populate name map
121                for (vrmllib::file::defs_t::iterator i=vfile.defs.begin(), e=vfile.defs.end(); i!=e; ++i)
122                        gNameMap[i->second] = i->first;
123
124                // search from SubMeshes
125                parseFile(&mesh, vfile);
126
127                if (mesh.getNumSubMeshes() == 0)
128                        throw "No SubMeshes were generated, aborting.";
129
130                log.logMessage("Exporting Mesh");
131                meshSer.exportMesh(&mesh, outname, true);
132
133                log.logMessage("Done.");
134        }
135        catch (const char *e) {
136                log.logMessage(LML_NORMAL, "Error: %s", e);
137                return 1;
138        }
139        catch (std::exception &e) {
140                log.logMessage(LML_NORMAL, "Exception: %s", e.what());
141                return 1;
142        }
143        catch (Exception &e) {
144                log.logMessage("Exception: " + e.getFullDescription());
145                return 1;
146        }
147}
148catch (Exception &e) {
149        std::cerr << "Exception: " << e.getFullDescription() << std::endl;
150        return 1;
151}
152catch (const char *e) {
153        std::cerr << e << std::endl;
154        return 1;
155}
156}
157
158void parseFile(Mesh *mesh, const vrmllib::file &file)
159{
160        for (vrmllib::file::roots_t::const_iterator i=file.roots.begin(), e=file.roots.end(); i!=e; ++i)
161                parseNode(mesh, *i);
162}
163
164void parseNode(Mesh *mesh, const vrmllib::node *n, Matrix4 m)
165{
166        if (const Transform *tr = dynamic_cast<const Transform *>(n)) {
167                // TODO: handle center, scaleOrientation
168
169                Matrix4 trans;
170                trans.makeTrans(vec(tr->translation));
171
172                Matrix4 scale = Matrix4::IDENTITY;
173                scale[0][0] = tr->scale.x;
174                scale[1][1] = tr->scale.y;
175                scale[2][2] = tr->scale.z;
176
177                Matrix3 rot3;
178                rot3.FromAxisAngle(vec(tr->rotation.vector), tr->rotation.radians);
179                Matrix4 rot = Matrix4::IDENTITY;
180                rot = rot3;
181
182                m = m * transMat(tr->translation) * transMat(tr->center)
183                        * rotMat(tr->rotation) * rotMat(tr->scaleOrientation) * scaleMat(tr->scale)
184                        * rotMat(tr->scaleOrientation, true) * transMat(tr->center, true);
185        }
186
187        if (const grouping_node *gn = dynamic_cast<const grouping_node *>(n)) {
188                for (std::vector<vrmllib::node *>::const_iterator
189                        i=gn->children.begin(), e=gn->children.end(); i!=e; ++i)
190                                parseNode(mesh, *i, m);
191
192        } else if (const Shape *sh = dynamic_cast<const Shape *>(n))
193                parseShape(mesh, sh, m);
194}
195
196void parseShape(Mesh *mesh, const Shape *sh, Matrix4 mat)
197{
198try
199{
200        LogManager &log = LogManager::getSingleton();
201        log.logMessage("Found a Shape...");
202
203        IndexedFaceSet *ifs = dynamic_cast<IndexedFaceSet *>(sh->geometry);
204        if (!ifs)
205                throw "Geometry was not an IndexedFaceSet, keep looking";
206
207        Coordinate *coord = dynamic_cast<Coordinate *>(ifs->coord);
208        if (!coord)
209                throw "Invalid Coordinate node";
210        if (coord->point.empty())
211                throw "No coordinates found, ignoring this Shape";
212
213        SubMesh *sub;
214        if (const String *name = findNameRecursive(sh)) {
215                log.logMessage("Creating SubMesh: " + *name);
216                sub = mesh->createSubMesh(*name);
217        } else {
218                log.logMessage("Creating unnamed SubMesh");
219                sub = mesh->createSubMesh();
220        }
221
222        Appearance *app = dynamic_cast<Appearance *>(sh->appearance);
223        TextureCoordinate *tcs = dynamic_cast<TextureCoordinate *>(ifs->texCoord);
224        Normal *norm = dynamic_cast<Normal *>(ifs->normal);
225        Color *color = dynamic_cast<Color *>(ifs->color);
226
227        String message = "Found: geometry";
228        if (tcs)
229                message += ", texcoords";
230        if (norm)
231                message += ", normals";
232        if (color)
233                message += ", colours";
234        log.logMessage(message);
235
236        if (!tcs && !norm && !color)
237                log.logMessage("Warning: OGRE will refuse to render SubMeshes that have neither\n"
238                        "\ttexture coordinates, normals or vertex colours.");
239
240        if (!norm) {
241                log.logMessage("Warning: No normals found.\n"
242                        "\tVRML dictates that normals should be generated, but this program\n"
243                        "\tdoes not do so. If you want the resulting mesh to contain normals,\n"
244                        "\tmake sure they are exported.");
245        }
246
247        // process material
248        static std::map<Appearance *, Ogre::MaterialPtr> matMap;
249
250        Ogre::MaterialPtr material = matMap[app];
251        if (!material->isNull() && app) {
252                log.logMessage("Using material " + material->getName());
253                sub->setMaterialName(material->getName());
254        } else {
255                String matName;
256                const String *mn;
257                if (mn = findName(app))
258                        matName = *mn;
259                else if (app && (mn = findName(app->material))) {
260                        static std::map<String, int> postfix;
261                        std::stringstream ss;
262                        int &num = postfix[*mn];
263                        ss << *mn << '/' << num++;
264                        matName = ss.str();
265                } else {
266                        static int matNum;
267                        std::stringstream ss;
268                        ss << gBaseName << '/' << matNum++;
269                        matName = ss.str();
270                        log.logMessage("No material name found, using " + matName);
271                }
272                log.logMessage("Reading material " + matName);
273
274                material = parseMaterial(app, matName);
275
276                sub->setMaterialName(matName);
277        }
278
279        FaceVec faces;
280        parseFaces(faces, ifs);
281
282        VertVec vertices;
283        TriVec triangles;
284
285        log.logMessage("Processing geometry...");
286        triangulateAndExpand(triangles, vertices, faces, sh);
287
288        copyToSubMesh(sub, triangles, vertices, sh, mat);
289
290        log.logMessage("Done with this SubMesh.");
291}
292catch (const char *e) {
293        LogManager::getSingleton().logMessage(e);
294}
295}
296
297void copyToSubMesh(SubMesh *sub, const TriVec &triangles, const VertVec &vertices,
298        const Shape *sh, const Matrix4 &mat)
299{
300        IndexedFaceSet *ifs = dynamic_cast<IndexedFaceSet *>(sh->geometry);
301        Coordinate *coord = dynamic_cast<Coordinate *>(ifs->coord);
302        TextureCoordinate *tcs = dynamic_cast<TextureCoordinate *>(ifs->texCoord);
303        Normal *norm = dynamic_cast<Normal *>(ifs->normal);
304        Color *color = dynamic_cast<Color *>(ifs->color);
305
306        int nvertices = vertices.size();
307        int nfaces = triangles.size();
308
309        GeometryData &geom = sub->geometry;
310        sub->useSharedVertices = false;
311        sub->numFaces = nfaces;
312        sub->faceVertexIndices = new unsigned short[nfaces*3];
313
314        geom.hasColours = color;
315        geom.hasNormals = norm;
316        geom.numTexCoords = tcs ? 1 : 0;
317        geom.numTexCoordDimensions[0] = 2;
318        geom.numVertices = nvertices;
319
320        geom.pVertices = new Real[nvertices*3];
321        if (tcs)
322                geom.pTexCoords[0] = new Real[nvertices*2];
323        if (norm)
324                geom.pNormals = new Real[nvertices*3];
325        if (color)
326                geom.pColours = new unsigned long[nvertices];
327
328        Matrix3 normMat;
329        mat.extract3x3Matrix(normMat);
330        normMat = normMat.Inverse().Transpose();
331
332        // populate face list
333        for (int i=0; i!=nfaces; ++i) {
334                unsigned short *f = sub->faceVertexIndices + i*3;
335                f[0] = triangles[i].vertices[0];
336                f[1] = triangles[i].vertices[1];
337                f[2] = triangles[i].vertices[2];
338        }
339
340        // populate vertex arrays
341        for (int i=0; i!=nvertices; ++i) {
342                const vertex &v = vertices[i];
343
344                Real *pos = geom.pVertices + i*3;
345                Real *tc = geom.pTexCoords[0] + i*2;
346                Real *n = geom.pNormals + i*3;
347                unsigned long *col = geom.pColours + i;
348
349                copyVec(pos, mat * vec(coord->point[v.pos]));
350                if (norm) {
351                        Vector3 t = normMat * vec(norm->vector[v.normal]);
352                        t.normalise();
353                        copyVec(n, t);
354                }
355                if (tcs)
356                        copyVec(tc, tcs->point[v.tc]);
357                if (color) {
358                        col3 c = color->color[v.colour];
359                        ColourValue cv(c.r, c.g, c.b);
360                        *col = cv.getAsLongRGBA();
361                }
362        }
363}
364
365void triangulateAndExpand(TriVec &triangles, VertVec &vertices, const FaceVec &faces, const Shape *sh)
366{
367        IndexedFaceSet *ifs = dynamic_cast<IndexedFaceSet *>(sh->geometry);
368        Coordinate *coord = dynamic_cast<Coordinate *>(ifs->coord);
369        TextureCoordinate *tcs = dynamic_cast<TextureCoordinate *>(ifs->texCoord);
370        Normal *norm = dynamic_cast<Normal *>(ifs->normal);
371        Color *color = dynamic_cast<Color *>(ifs->color);
372
373        VertMap vertexMap;
374
375        // triangulate and expand vertices
376        for (FaceVec::const_iterator f=faces.begin(), e=faces.end(); f!=e; ++f) {
377                int faceNr = f - faces.begin();
378                int triVertNr = 0;
379                int triVerts[2] = { -1, -1 };
380                for (IntVec::const_iterator i = f->indices.begin(), e=f->indices.end(); i!=e; ++i, ++triVertNr) {
381                        int triVertNr = i - f->indices.begin();
382                        int index = *i;
383
384                        vertex vert;
385
386                        // get full indices for vertex data
387                        vert.pos = ifs->coordIndex[index];
388                        vert.normal = norm ? getIndex(ifs->coordIndex, ifs->normalIndex,
389                                ifs->normalPerVertex, faceNr, index) : 0;
390                        vert.colour = color ? getIndex(ifs->coordIndex, ifs->colorIndex,
391                                ifs->colorPerVertex, faceNr, index) : 0;
392                        vert.tc = tcs ? getIndex(ifs->coordIndex, ifs->texCoordIndex,
393                                true, faceNr, index) : 0;
394
395                        // avoid duplication
396                        int nvert = vertexMap.size();
397                        int &vpos = vertexMap[vert];
398                        if (nvert != vertexMap.size()) {
399                                vpos = vertices.size();
400                                vertices.push_back(vert);
401                        }
402
403                        // emit triangle (maybe)
404                        if (triVertNr == 0)
405                                triVerts[0] = vpos;
406                        else if (triVertNr == 1)
407                                triVerts[1] = vpos;
408                        else {
409                                triangle t;
410                                t.vertices[0] = triVerts[0];
411                                t.vertices[1] = triVerts[1];
412                                t.vertices[2] = vpos;
413
414                                if (!ifs->ccw)
415                                        std::swap(t.vertices[1], t.vertices[2]);
416
417                                triangles.push_back(t);
418
419                                triVerts[1] = vpos;
420                        }
421                }
422        }
423}
424
425int getIndex(const IntVec &coordIndex, const IntVec &vec, bool perVertex, int facenr, int index)
426{
427        if (!perVertex) {
428                if (!vec.empty())
429                        return vec[facenr];
430                else
431                        return facenr;
432        } else {
433                if (!vec.empty())
434                        return vec[index];
435                else
436                        return coordIndex[index];
437        }
438}
439
440const String *findName(const vrmllib::node *n)
441{
442        NameMap::const_iterator i = gNameMap.find(n);
443        if (i == gNameMap.end())
444                return 0;
445        else
446                return &i->second;
447}
448
449const String *findNameRecursive(const vrmllib::node *n)
450{
451        if (const String *name = findName(n))
452                return name;
453        else if (n->parent)
454                return findNameRecursive(n->parent);
455        else
456                return 0;
457}
458
459void parseFaces(FaceVec &faces, const IndexedFaceSet *ifs)
460{
461        face f;
462        for (IntVec::const_iterator i=ifs->coordIndex.begin(), e=ifs->coordIndex.end(); i!=e; ++i) {
463                if (*i == -1) {
464                        faces.resize(faces.size()+1);
465                        faces.back().indices.swap(f.indices);
466                } else
467                        f.indices.push_back(i - ifs->coordIndex.begin());
468        }
469        if (!f.indices.empty()) {
470                faces.resize(faces.size()+1);
471                faces.back().indices.swap(f.indices);
472        }
473}
474
475Ogre::MaterialPtr parseMaterial(const Appearance *app, const String &name)
476{
477        vrmllib::Material *vm = app ? dynamic_cast<vrmllib::Material *>(app->material) : 0;
478        vrmllib::ImageTexture *texture = app ? dynamic_cast<vrmllib::ImageTexture *>(app->texture) : 0;
479
480        Ogre::MaterialPtr m = MaterialManager::getSingleton().create(name,
481        ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
482
483        ColourValue diffuse = texture ? ColourValue::White : col(vm->diffuseColor);
484                // diffuse colour is unused by VRML when a texture is avaliable,
485                // set to white to give the same effect in OGRE
486
487        ColourValue a = diffuse;
488        a.r *= vm->ambientIntensity;
489        a.g *= vm->ambientIntensity;
490        a.b *= vm->ambientIntensity;
491        m->setAmbient(a);
492        m->setDiffuse(diffuse);
493        m->setSelfIllumination(col(vm->emissiveColor));
494        m->setShininess(vm->shininess);
495        m->setSpecular(col(vm->specularColor));
496
497        m->setLightingEnabled(app);
498
499        if (texture && !texture->url.empty()) {
500                String texName = texture->url.front();
501                size_t p = texName.find_last_of("/\\");
502                if (p != texName.npos) {
503                        LogManager::getSingleton().logMessage("Stripping path from texture " + texName);
504                        texName.erase(0, p+1);
505                }
506
507                LogManager::getSingleton().logMessage("Adding texture layer for " + texName);
508
509                Ogre::TextureUnitState *l = m->addTextureLayer(texName);
510                l->setTextureAddressingMode(texture->repeatS ?
511                        Ogre::TextureUnitState::TAM_WRAP : Ogre::TextureUnitState::TAM_CLAMP);
512        }
513
514        return m;
515}
516
517Matrix4 transMat(vrmllib::vec3 v, bool inverse)
518{
519        if (inverse)
520                return Matrix4::getTrans(-v.x, -v.y, -v.z);
521        else
522                return Matrix4::getTrans(v.x, v.y, v.z);
523}
524
525Matrix4 scaleMat(vrmllib::vec3 v, bool inverse)
526{
527        if (inverse)
528                return Matrix4::getScale(1/v.x, 1/v.y, 1/v.z);
529        else
530                return Matrix4::getScale(v.x, v.y, v.z);
531}
532
533Matrix4 rotMat(vrmllib::rot r, bool inverse)
534{
535        Matrix3 rot3;
536        rot3.FromAxisAngle(vec(r.vector), inverse ? -r.radians : r.radians);
537        Matrix4 rot = Matrix4::IDENTITY;
538        rot = rot3;
539        return rot;
540}
Note: See TracBrowser for help on using the repository browser.