root/OpenSceneGraph/trunk/src/osgPlugins/lwo/ReaderWriterLWO.cpp @ 13041

Revision 13041, 11.9 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// -*-c++-*-
2
3/*
4 * Lightwave Object loader for Open Scene Graph
5 *
6 * Copyright (C) 2001 Ulrich Hertlein <u.hertlein@web.de>
7 * Improved LWO2 reader is (C) 2003-2004 Marco Jez <marco.jez@poste.it>
8 *
9 * The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for
10 * real-time rendering of large 3D photo-realistic models.
11 * The OSG homepage is http://www.openscenegraph.org/
12 */
13
14#if defined(_MSC_VER)
15    #pragma warning( disable : 4786 )
16#endif
17
18#include <string>
19#include <memory>
20#include <sstream>
21#include <algorithm>
22
23#include <osg/Notify>
24#include <osg/Node>
25#include <osg/Group>
26#include <osg/Geode>
27#include <osg/Group>
28#include <osg/Texture2D>
29#include <osg/Geometry>
30#include <osg/StateSet>
31
32#include <osgDB/Registry>
33#include <osgDB/ReadFile>
34#include <osgDB/FileNameUtils>
35#include <osgDB/FileUtils>
36
37#include <osgUtil/SmoothingVisitor>
38#include <osgUtil/Tessellator>
39
40#include <string.h>
41
42#include "Converter.h"
43#include "VertexMap.h"
44
45#include "old_lw.h"
46#include "old_Lwo2.h"
47
48class ReaderWriterLWO : public osgDB::ReaderWriter
49{
50public:
51    ReaderWriterLWO()
52    {
53        supportsExtension("lwo","Lightwave object format");
54        supportsExtension("lw","Lightwave object format");
55        supportsExtension("geo","Lightwave geometry format");
56    }
57
58    virtual const char* className() const { return "Lightwave Object Reader"; }
59
60    virtual ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const
61    {
62        std::string ext = osgDB::getLowerCaseFileExtension(file);
63        if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
64
65        std::string fileName = osgDB::findDataFile( file, options );
66        if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
67
68        // code for setting up the database path so that internally referenced file are searched for on relative paths.
69        osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
70        local_opt->setDatabasePath(osgDB::getFilePath(fileName));
71
72        ReadResult result = readNode_LWO1(fileName,local_opt.get());
73        if (result.success()) return result;
74
75        if (!options || options->getOptionString() != "USE_OLD_READER") {
76            ReadResult result = readNode_LWO2(fileName, local_opt.get());
77            if (result.success()) return result;
78        }
79
80        return readNode_old_LWO2(fileName, local_opt.get());
81    }
82
83    lwosg::Converter::Options parse_options(const Options *options) const;
84
85    virtual ReadResult readNode_LWO2(const std::string& fileName, const osgDB::ReaderWriter::Options*) const;
86    virtual ReadResult readNode_old_LWO2(const std::string& fileName, const osgDB::ReaderWriter::Options*) const;
87    virtual ReadResult readNode_LWO1(const std::string& fileName, const osgDB::ReaderWriter::Options*) const;
88
89protected:
90
91
92
93};
94
95lwosg::Converter::Options ReaderWriterLWO::parse_options(const Options *options) const
96{
97    lwosg::Converter::Options conv_options;
98
99    if (options) {
100        std::istringstream iss(options->getOptionString());
101        std::string opt;
102        while (iss >> opt) {
103            if (opt == "COMBINE_GEODES")           conv_options.combine_geodes = true;
104            if (opt == "FORCE_ARB_COMPRESSION")    conv_options.force_arb_compression = true;
105            if (opt == "USE_OSGFX")                conv_options.use_osgfx = true;
106            if (opt == "NO_LIGHTMODEL_ATTRIBUTE")  conv_options.apply_light_model = false;
107            if (opt == "BIND_TEXTURE_MAP")
108            {
109                std::string mapname;
110                int unit;
111                if (iss >> mapname >> unit)
112                {
113                    conv_options.texturemap_bindings.insert(lwosg::VertexMap_binding_map::value_type(mapname,  unit));
114                }
115            }
116            if (opt == "MAX_TEXTURE_UNITS") {
117                int n;
118                if (iss >> n) {
119                    conv_options.max_tex_units = n;
120                }
121            }
122        }
123    }
124
125    return conv_options;
126}
127
128
129// register with Registry to instantiate the above reader/writer.
130REGISTER_OSGPLUGIN(lwo, ReaderWriterLWO)
131
132osgDB::ReaderWriter::ReadResult ReaderWriterLWO::readNode_LWO2(const std::string &fileName, const osgDB::ReaderWriter::Options *options) const
133{
134    lwosg::Converter::Options conv_options = parse_options(options);
135
136    lwosg::Converter converter(conv_options, options);
137    osg::ref_ptr<osg::Node> node = converter.convert(fileName);
138    if (node.valid()) {
139        return node.release();
140    }
141
142    return ReadResult::FILE_NOT_HANDLED;
143}
144
145
146osgDB::ReaderWriter::ReadResult ReaderWriterLWO::readNode_old_LWO2(const std::string& fileName, const osgDB::ReaderWriter::Options*) const
147{
148    std::auto_ptr<Lwo2> lwo2(new Lwo2());
149    if (lwo2->ReadFile(fileName))
150    {
151        osg::ref_ptr<Group> group = new osg::Group();
152        if (lwo2->GenerateGroup(*group)) return group.release();
153    }
154    return ReadResult::FILE_NOT_HANDLED;
155}
156
157
158
159
160
161// collect all the data relavent to a particular osg::Geometry being created.
162struct GeometryCollection
163{
164    GeometryCollection():
165        _numPrimitives(0),
166        _numPrimitivesWithTexCoords(0),
167        _numPoints(0),
168        _texturesActive(false),
169        _vertices(osg::Vec3Array::iterator()),
170        _texcoords(osg::Vec2Array::iterator()),
171        _coordCount(0),
172        _geom(0) {}
173
174    int                         _numPrimitives;
175    int                         _numPrimitivesWithTexCoords;
176    int                         _numPoints;
177    bool                        _texturesActive;
178    osg::Vec3Array::iterator    _vertices;
179    osg::Vec2Array::iterator    _texcoords;
180    int                         _coordCount;
181    osg::Geometry*              _geom;
182};
183
184
185
186// read file and convert to OSG.
187osgDB::ReaderWriter::ReadResult ReaderWriterLWO::readNode_LWO1(const std::string& fileName, const osgDB::ReaderWriter::Options*) const
188{
189    lwObject* lw = lw_object_read(fileName.c_str(),osg::notify(osg::INFO));
190    if (!lw)
191        return ReadResult::FILE_NOT_HANDLED;
192
193    OSG_INFO << "faces " << lw->face_cnt << std::endl;
194    OSG_INFO << "materials " << lw->material_cnt << std::endl;
195    OSG_INFO << "vertices " << lw->vertex_cnt << std::endl;
196
197    typedef std::map<int,GeometryCollection> MaterialToGeometryCollectionMap;
198    MaterialToGeometryCollectionMap mtgcm;
199
200    // bin the indices for each material into the mtis;
201    int i;
202    for (i = 0; i < lw->face_cnt; ++i)
203    {
204        lwFace& face = lw->face[i];
205        if (face.index_cnt>=3)
206        {
207            GeometryCollection& gc = mtgcm[face.material];
208            gc._numPoints += face.index_cnt;
209            gc._numPrimitives += 1;
210            if (face.texcoord) gc._numPrimitivesWithTexCoords += 1;
211        }
212    }
213
214    MaterialToGeometryCollectionMap::iterator itr;
215    for(itr=mtgcm.begin(); itr!=mtgcm.end(); ++itr)
216    {
217        GeometryCollection& gc = itr->second;
218
219        if (gc._numPrimitives)
220        {
221            lwMaterial& lw_material = lw->material[itr->first];
222
223            gc._geom = new osg::Geometry;
224
225            osg::Vec3Array* vertArray = new osg::Vec3Array(gc._numPoints);
226            gc._vertices = vertArray->begin();
227            gc._geom->setVertexArray(vertArray);
228
229            // set up color.
230            osg::Vec4Array* colors = new osg::Vec4Array(1);
231            (*colors)[0].set(lw_material.r,
232                             lw_material.g,
233                             lw_material.b,
234                             1.0f);
235
236            gc._geom->setColorArray(colors);
237            gc._geom->setColorBinding(osg::Geometry::BIND_OVERALL);
238
239            // set up texture if needed.
240            if (gc._numPrimitivesWithTexCoords==gc._numPrimitives)
241            {
242                if (lw_material.ctex.flags && strlen(lw_material.ctex.name)!=0)
243                {
244                    OSG_INFO << "ctex " << lw_material.ctex.name << std::endl;
245                    osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile(lw_material.ctex.name);
246                    if (image.valid())
247                    {
248                        // create state
249                        osg::StateSet* stateset = new osg::StateSet;
250
251                        // create texture
252                        osg::Texture2D* texture = new osg::Texture2D;
253                        texture->setImage(image.get());
254
255                        // texture wrap mode
256                        static osg::Texture::WrapMode mode[] = {
257                            osg::Texture::CLAMP,
258                            osg::Texture::CLAMP,
259                            osg::Texture::REPEAT,
260                            osg::Texture::MIRROR
261                        };
262                        texture->setWrap(osg::Texture::WRAP_S,
263                                         mode[lw_material.ctex.u_wrap]);
264                        texture->setWrap(osg::Texture::WRAP_T,
265                                         mode[lw_material.ctex.v_wrap]);
266
267                        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
268                        gc._texturesActive=true;
269
270                        gc._geom->setStateSet(stateset);
271
272                        osg::Vec2Array* texcoordArray = new osg::Vec2Array(gc._numPoints);
273                        gc._texcoords = texcoordArray->begin();
274                        gc._geom->setTexCoordArray(0,texcoordArray);
275                    }
276                }
277            }
278        }
279    }
280
281
282    for (i = 0; i < lw->face_cnt; ++i)
283    {
284        lwFace& face = lw->face[i];
285        if (face.index_cnt>=3)
286        {
287            GeometryCollection& gc = mtgcm[face.material];
288
289            osg::PrimitiveSet::Mode mode;
290            switch(face.index_cnt)
291            {
292                case(0):
293                    mode = osg::PrimitiveSet::POINTS;
294                    break;
295                case(1):
296                    mode = osg::PrimitiveSet::POINTS;
297                    break;
298                case(2):
299                    mode = osg::PrimitiveSet::LINES;
300                    break;
301                case(3):
302                    mode = osg::PrimitiveSet::TRIANGLES;
303                    break;
304                case(4):
305                    mode = osg::PrimitiveSet::QUADS;
306                    break;
307                default:
308                    mode = osg::PrimitiveSet::POLYGON;
309                    break;
310            }
311
312            gc._geom->addPrimitiveSet(new osg::DrawArrays(mode,gc._coordCount,face.index_cnt));
313            gc._coordCount += face.index_cnt;
314
315            // From the spec_low.lxt :
316            //   "By convention, the +X direction is to the right or east, the +Y
317            //    direction is upward, and the +Z direction is forward or north"
318            // However, the osg sticks to the more conventional, y to the north,
319            // z upwards, x is the same - rigth/east.  To handle this difference
320            // simple exchange osg_z for lwo_y, and osg_y for lwo_z.
321
322            // add the corners in reverse order to reverse the windings, to keep the anticlockwise rotation of polys.
323            int j;
324            for(j=face.index_cnt-1;j>=0;--j)
325            {
326                (*gc._vertices++).set(lw->vertex[face.index[j]*3], lw->vertex[face.index[j]*3+2], lw->vertex[face.index[j]*3+1]);
327            }
328
329            if (gc._texturesActive && face.texcoord)
330            {
331                for(j=face.index_cnt-1;j>=0;--j)
332                {
333                    (*gc._texcoords++).set(face.texcoord[j*2],face.texcoord[j*2+1]);
334                }
335            }
336        }
337    }
338
339    osg::Geode* geode = new osg::Geode;
340
341    osgUtil::Tessellator tessellator;
342
343    // add everthing into the Geode.
344    osgUtil::SmoothingVisitor smoother;
345    for(itr=mtgcm.begin();
346        itr!=mtgcm.end();
347        ++itr)
348    {
349        GeometryCollection& gc = itr->second;
350        if (gc._geom)
351        {
352
353            tessellator.retessellatePolygons(*gc._geom);
354
355            smoother.smooth(*gc._geom);
356
357            geode->addDrawable(gc._geom);
358        }
359
360    }
361
362    // free
363    lw_object_free(lw);
364
365    return geode;
366}
Note: See TracBrowser for help on using the browser.