root/OpenSceneGraph/trunk/src/osgPlugins/OpenFlight/ReaderWriterFLT.cpp @ 12297

Revision 12297, 27.1 kB (checked in by robert, 4 years ago)

From Magnus Kessler, "A few minor fixes in the documentation strings of ReaderWriterFLT.cpp"

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14//
15// OpenFlight® loader for OpenSceneGraph
16//
17//  Copyright (C) 2005-2007  Brede Johansen
18//
19
20#include <stdexcept>
21#include <osg/Notify>
22#include <osg/ProxyNode>
23#include <osgDB/FileNameUtils>
24#include <osgDB/FileUtils>
25#include <osgDB/Registry>
26#include <osgDB/ReadFile>
27#include <OpenThreads/ReentrantMutex>
28#include <osgUtil/Optimizer>
29
30#include "Registry.h"
31#include "Document.h"
32#include "RecordInputStream.h"
33#include "DataOutputStream.h"
34#include "FltExportVisitor.h"
35#include "ExportOptions.h"
36
37#define SERIALIZER() OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_serializerMutex) 
38
39using namespace flt;
40using namespace osg;
41using namespace osgDB;
42
43// pull in symbols from attr plugin
44USE_OSGPLUGIN(attr)
45
46// pull in symbols from individual .o's to enable the static build to work
47// note, following USE_FLTRECORD list was generated by running:
48// grep REGISTER_FLTRECORD * -h | grep -v "#define" | sed 's/REGISTER_FLTRECORD/USE_FLTRECORD/g'
49USE_FLTRECORD(Comment, COMMENT_OP)
50USE_FLTRECORD(LongID, LONG_ID_OP)
51USE_FLTRECORD(Matrix, MATRIX_OP)
52USE_FLTRECORD(Multitexture, MULTITEXTURE_OP)
53USE_FLTRECORD(UVList, UV_LIST_OP)
54USE_FLTRECORD(Replicate, REPLICATE_OP)
55USE_FLTRECORD(DummyRecord, OLD_TRANSLATE2_OP)
56USE_FLTRECORD(DummyRecord, OLD_ROTATE_ABOUT_POINT_OP)
57USE_FLTRECORD(DummyRecord, OLD_ROTATE_ABOUT_EDGE_OP)
58USE_FLTRECORD(DummyRecord, OLD_SCALE_OP)
59USE_FLTRECORD(DummyRecord, OLD_TRANSLATE_OP)
60USE_FLTRECORD(DummyRecord, OLD_NONUNIFORM_SCALE_OP)
61USE_FLTRECORD(DummyRecord, OLD_ROTATE_ABOUT_POINT2_OP)
62USE_FLTRECORD(DummyRecord, OLD_ROTATE_SCALE_TO_POINT_OP)
63USE_FLTRECORD(DummyRecord, OLD_PUT_TRANSFORM_OP)
64USE_FLTRECORD(DummyRecord, OLD_BOUNDING_BOX_OP)
65USE_FLTRECORD(DummyRecord, INDEXED_STRING_OP)
66USE_FLTRECORD(DummyRecord, ROAD_ZONE_OP)
67USE_FLTRECORD(DummyRecord, ROTATE_ABOUT_EDGE_OP)
68USE_FLTRECORD(DummyRecord, TRANSLATE_OP)
69USE_FLTRECORD(DummyRecord, NONUNIFORM_SCALE_OP)
70USE_FLTRECORD(DummyRecord, ROTATE_ABOUT_POINT_OP)
71USE_FLTRECORD(DummyRecord, ROTATE_SCALE_TO_POINT_OP)
72USE_FLTRECORD(DummyRecord, PUT_TRANSFORM_OP)
73USE_FLTRECORD(DummyRecord, GENERAL_MATRIX_OP)
74USE_FLTRECORD(DummyRecord, VECTOR_OP)
75USE_FLTRECORD(DummyRecord, BOUNDING_BOX_OP)
76USE_FLTRECORD(DummyRecord, BOUNDING_SPHERE_OP)
77USE_FLTRECORD(DummyRecord, BOUNDING_CYLINDER_OP)
78USE_FLTRECORD(DummyRecord, BOUNDING_CONVEX_HULL_OP)
79USE_FLTRECORD(DummyRecord, BOUNDING_HISTOGRAM)
80USE_FLTRECORD(DummyRecord, BOUNDING_VOLUME_CENTER_OP)
81USE_FLTRECORD(DummyRecord, BOUNDING_VOLUME_ORIENTATION_OP)
82USE_FLTRECORD(DummyRecord, HISTOGRAM_BOUNDING_VOLUME_OP)
83USE_FLTRECORD(PushLevel, PUSH_LEVEL_OP)
84USE_FLTRECORD(PopLevel, POP_LEVEL_OP)
85USE_FLTRECORD(PushSubface, PUSH_SUBFACE_OP)
86USE_FLTRECORD(PopSubface, POP_SUBFACE_OP)
87USE_FLTRECORD(PushExtension, PUSH_EXTENSION_OP)
88USE_FLTRECORD(PopExtension, POP_EXTENSION_OP)
89USE_FLTRECORD(PushAttribute, PUSH_ATTRIBUTE_OP)
90USE_FLTRECORD(PopAttribute, POP_ATTRIBUTE_OP)
91USE_FLTRECORD(Face, FACE_OP)
92USE_FLTRECORD(VertexListRecord, VERTEX_LIST_OP)
93USE_FLTRECORD(MorphVertexList, MORPH_VERTEX_LIST_OP)
94USE_FLTRECORD(Mesh, MESH_OP)
95USE_FLTRECORD(LocalVertexPool, LOCAL_VERTEX_POOL_OP)
96USE_FLTRECORD(MeshPrimitive, MESH_PRIMITIVE_OP)
97USE_FLTRECORD(LightPoint, LIGHT_POINT_OP)
98USE_FLTRECORD(IndexedLightPoint, INDEXED_LIGHT_POINT_OP)
99USE_FLTRECORD(LightPointSystem, LIGHT_POINT_SYSTEM_OP)
100USE_FLTRECORD(VertexPalette, VERTEX_PALETTE_OP)
101USE_FLTRECORD(ColorPalette, COLOR_PALETTE_OP)
102USE_FLTRECORD(NameTable, NAME_TABLE_OP)
103USE_FLTRECORD(MaterialPalette, MATERIAL_PALETTE_OP)
104USE_FLTRECORD(OldMaterialPalette, OLD_MATERIAL_PALETTE_OP)
105USE_FLTRECORD(TexturePalette, TEXTURE_PALETTE_OP)
106USE_FLTRECORD(EyepointAndTrackplanePalette, EYEPOINT_AND_TRACKPLANE_PALETTE_OP)
107USE_FLTRECORD(LinkagePalette, LINKAGE_PALETTE_OP)
108USE_FLTRECORD(SoundPalette, SOUND_PALETTE_OP)
109USE_FLTRECORD(LightSourcePalette, LIGHT_SOURCE_PALETTE_OP)
110USE_FLTRECORD(LightPointAppearancePalette, LIGHT_POINT_APPEARANCE_PALETTE_OP)
111USE_FLTRECORD(LightPointAnimationPalette, LIGHT_POINT_ANIMATION_PALETTE_OP)
112USE_FLTRECORD(LineStylePalette, LINE_STYLE_PALETTE_OP)
113USE_FLTRECORD(TextureMappingPalette, TEXTURE_MAPPING_PALETTE_OP)
114USE_FLTRECORD(ShaderPalette, SHADER_PALETTE_OP)
115USE_FLTRECORD(Header, HEADER_OP)
116USE_FLTRECORD(Group, GROUP_OP)
117USE_FLTRECORD(DegreeOfFreedom, DOF_OP)
118USE_FLTRECORD(LevelOfDetail, LOD_OP)
119USE_FLTRECORD(OldLevelOfDetail, OLD_LOD_OP)
120USE_FLTRECORD(Switch, SWITCH_OP)
121USE_FLTRECORD(ExternalReference, EXTERNAL_REFERENCE_OP)
122USE_FLTRECORD(InstanceDefinition, INSTANCE_DEFINITION_OP)
123USE_FLTRECORD(InstanceReference, INSTANCE_REFERENCE_OP)
124USE_FLTRECORD(Extension, EXTENSION_OP)
125USE_FLTRECORD(Object, OBJECT_OP)
126USE_FLTRECORD(LightSource, LIGHT_SOURCE_OP)
127USE_FLTRECORD(DummyRecord, 103)
128USE_FLTRECORD(DummyRecord, 104)
129USE_FLTRECORD(DummyRecord, 117)
130USE_FLTRECORD(DummyRecord, 118)
131USE_FLTRECORD(DummyRecord, 120)
132USE_FLTRECORD(DummyRecord, 121)
133USE_FLTRECORD(DummyRecord, 124)
134USE_FLTRECORD(DummyRecord, 125)
135USE_FLTRECORD(RoadSegment, ROAD_SEGMENT_OP)
136USE_FLTRECORD(RoadConstruction, ROAD_CONSTRUCTION_OP)
137USE_FLTRECORD(RoadPath, ROAD_PATH_OP)
138USE_FLTRECORD(VertexC, VERTEX_C_OP)
139USE_FLTRECORD(VertexCN, VERTEX_CN_OP)
140USE_FLTRECORD(VertexCT, VERTEX_CT_OP)
141USE_FLTRECORD(VertexCNT, VERTEX_CNT_OP)
142USE_FLTRECORD(AbsoluteVertex, OLD_ABSOLUTE_VERTEX_OP)
143USE_FLTRECORD(ShadedVertex, OLD_SHADED_VERTEX_OP)
144USE_FLTRECORD(NormalVertex, OLD_NORMAL_VERTEX_OP)
145
146
147
148class ReadExternalsVisitor : public osg::NodeVisitor
149{
150    osg::ref_ptr<ReaderWriter::Options> _options;
151    bool _cloneExternalReferences;
152
153public:
154
155    ReadExternalsVisitor(ReaderWriter::Options* options) :
156        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
157        _options(options),
158        _cloneExternalReferences(false)
159    {
160        if (options)
161            _cloneExternalReferences = (options->getOptionString().find("cloneExternalReferences")!=std::string::npos);
162    }
163
164    virtual ~ReadExternalsVisitor() {}
165
166    virtual void apply(ProxyNode& node)
167    {
168        // Transfer ownership of pools.
169        _options->setUserData( node.getUserData() );
170        node.setUserData(NULL);
171
172        for (unsigned int pos=0; pos<node.getNumFileNames(); pos++)
173        {
174            std::string filename = node.getFileName(pos);
175
176            // read external
177            osg::ref_ptr<osg::Node> external = osgDB::readNodeFile(filename,_options.get());
178            if (external.valid())
179            {
180                if (_cloneExternalReferences)
181                    external = dynamic_cast<osg::Node*>(external->clone(osg::CopyOp(osg::CopyOp::DEEP_COPY_NODES)));
182
183                node.addChild(external.get());
184            }
185        }
186    }
187};
188
189
190
191/*!
192
193FLTReaderWriter supports importing and exporting OSG scene graphs
194from/to OpenFlight files.
195
196<table>
197  <tr>
198    <th></th>
199    <th align="center">Node</th>
200    <th align="center">Object</th>
201    <th align="center">Image</th>
202    <th align="center">HeightField</th>
203  </tr>
204  <tr>
205    <td align="right">Read</td>
206    <td align="center"><strong>X</strong></td>
207    <td></td>
208    <td></td>
209    <td></td>
210  </tr>
211  <tr>
212    <td align="right">Write</td>
213    <td align="center"><strong>X</strong></td>
214    <td></td>
215    <td></td>
216    <td></td>
217  </tr>
218</table>
219
220*/
221
222class FLTReaderWriter : public ReaderWriter
223{
224    public:
225        FLTReaderWriter()
226          : _implicitPath( "." )
227        {
228            supportsExtension("flt","OpenFlight format");
229           
230            supportsOption("clampToEdge","Import option");
231            supportsOption("keepExternalReferences","Import option");
232            supportsOption("preserveFace","Import option");
233            supportsOption("preserveObject","Import option");
234            supportsOption("replaceDoubleSidedPolys","Import option");
235            supportsOption("dofAnimation","Import option");
236            supportsOption("billboardCenter","Import option");
237            supportsOption("noTextureAlphaForTransparancyBinning","Import option");
238            supportsOption("readObjectRecordData","Import option");
239            supportsOption("noUnitsConversion","Import option");
240            supportsOption("convertToFeet","Import option");
241            supportsOption("convertToInches","Import option");
242            supportsOption("convertToMeters","Import option");
243            supportsOption("convertToKilometers","Import option");
244            supportsOption("convertToNauticalMiles","Import option");
245
246            supportsOption( "version=<ver>", "Export option: Specifies the version of the output OpenFlight file. Supported values include 15.7, 15.8, and 16.1. Default is 16.1. Example: \"version=15.8\"." );
247            supportsOption( "units=<units>", "Export option: Specifies the contents of the Units field of the OpenFlight header record. Valid values include INCHES, FEET, METERS, KILOMETERS, and NAUTICAL_MILES. Default is METERS. Example: \"units=METERS\"." );
248            supportsOption( "validate", "Export option: If present in the Options string, the plugin does not write an OpenFlight file. Instead, it returns an indication of the scene graph's suitability for OpenFlight export." );
249            supportsOption( "tempDir=<dir>", "Export option: Specifies the directory to use for creation of temporary files. If not specified, the directory is taken from the file name. If the file doesn't contain a path, the current working directory is used. Applications should set this to the name of their app-specific temp directory. If the path contains spaces, use double quotes to ensure correct parsing. Examples: \"tempDir=/tmp\", \"tempDir=\"C:\\My Temp Dir\"." );
250            supportsOption( "lighting=<ON|OFF>", "Export option: Specifies a default enable/disable state for lighting, for Nodes in the exported scene graph that don't set it explicitly. By default, the exporter assumes lighting is enabled (GL_LIGHTING ON). Set this to either ON or OFF. Example: \"lighting=OFF\"." );
251            supportsOption( "stripTextureFilePath", "Export option: If present in the Options string, the exporter strips the path from texture file names, and writes only the texture file name to the FLT Texture Palette. By default, the exporter doesn't strip the path, and the name written to the Texture Palette is taken directly from the osg::Image object referenced by the osg::Texture2D StateAttribute." );
252        }
253
254        virtual const char* className() const { return "FLT Reader/Writer"; }
255
256        virtual bool acceptsExtension(const std::string& extension) const
257        {
258            return equalCaseInsensitive(extension,"flt") || extension.empty();
259        }
260
261        virtual ReadResult readObject(const std::string& file, const Options* options) const
262        {
263            return readNode(file, options);
264        }
265       
266        virtual ReadResult readNode(const std::string& file, const Options* options) const
267        {
268            SERIALIZER();
269
270            std::string ext = osgDB::getLowerCaseFileExtension(file);
271            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
272
273            std::string fileName = osgDB::findDataFile(file, options);
274            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
275
276            // in local cache?
277            {
278                osg::Node* node = flt::Registry::instance()->getExternalFromLocalCache(fileName);
279                if (node)
280                    return ReadResult(node, ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE);
281            }
282
283            // setting up the database path so that internally referenced file are searched for on relative paths.
284            osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
285            local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));
286
287            ReadResult rr;
288
289            // read file
290            {
291                osgDB::ifstream istream;
292                istream.imbue(std::locale::classic());
293                istream.open(fileName.c_str(), std::ios::in | std::ios::binary);
294
295                if (istream)
296                {
297                    rr = readNode(istream,local_opt.get());
298                }
299            }
300
301            static int nestedExternalsLevel = 0;
302            if (rr.success())
303            {
304                // add to local cache.
305                flt::Registry::instance()->addExternalToLocalCache(fileName,rr.getNode());
306       
307                bool keepExternalReferences = false;
308                if (options)
309                    keepExternalReferences = (options->getOptionString().find("keepExternalReferences")!=std::string::npos);
310
311
312                if ( !keepExternalReferences )
313                {
314                    OSG_DEBUG << "keepExternalReferences not found, so externals will be re-readed"<<std::endl;
315                    // read externals.
316                    if (rr.getNode())
317                    {
318                        nestedExternalsLevel++;
319                        ReadExternalsVisitor visitor(local_opt.get());
320                        rr.getNode()->accept(visitor);
321                        nestedExternalsLevel--;
322                    }
323                }
324                else
325                {
326                    OSG_DEBUG << "keepExternalReferences found, so externals will be left as ProxyNodes"<<std::endl;   
327                }
328            }
329
330            // clear local cache.
331            if (nestedExternalsLevel==0)
332                flt::Registry::instance()->clearLocalCache();
333
334            return rr;
335        }
336       
337        virtual ReadResult readObject(std::istream& fin, const Options* options) const
338        {
339            return readNode(fin, options);
340        }
341       
342        virtual ReadResult readNode(std::istream& fin, const Options* options) const
343        {
344            Document document;
345            document.setOptions(options);
346
347            // option string and parent pools
348            if (options)
349            {
350                const char readerMsg[] = "flt reader option: ";
351               
352                document.setReplaceClampWithClampToEdge((options->getOptionString().find("clampToEdge")!=std::string::npos));
353                OSG_DEBUG << readerMsg << "clampToEdge=" << document.getReplaceClampWithClampToEdge() << std::endl;
354
355                document.setKeepExternalReferences((options->getOptionString().find("keepExternalReferences")!=std::string::npos));
356                OSG_DEBUG << readerMsg << "keepExternalReferences=" << document.getKeepExternalReferences() << std::endl;
357
358                document.setPreserveFace((options->getOptionString().find("preserveFace")!=std::string::npos));
359                OSG_DEBUG << readerMsg << "preserveFace=" << document.getPreserveFace() << std::endl;
360
361                document.setPreserveObject((options->getOptionString().find("preserveObject")!=std::string::npos));
362                OSG_DEBUG << readerMsg << "preserveObject=" << document.getPreserveObject() << std::endl;
363
364                document.setReplaceDoubleSidedPolys((options->getOptionString().find("replaceDoubleSidedPolys")!=std::string::npos));
365                OSG_DEBUG  << readerMsg << "replaceDoubleSidedPolys=" << document.getReplaceDoubleSidedPolys() << std::endl;
366
367                document.setDefaultDOFAnimationState((options->getOptionString().find("dofAnimation")!=std::string::npos));
368                OSG_DEBUG << readerMsg << "dofAnimation=" << document.getDefaultDOFAnimationState() << std::endl;
369
370                document.setUseBillboardCenter((options->getOptionString().find("billboardCenter")!=std::string::npos));
371                OSG_DEBUG << readerMsg << "billboardCenter=" << document.getUseBillboardCenter() << std::endl;
372
373                document.setUseTextureAlphaForTransparancyBinning(options->getOptionString().find("noTextureAlphaForTransparancyBinning")==std::string::npos);
374                OSG_DEBUG << readerMsg << "noTextureAlphaForTransparancyBinning=" << !document.getUseTextureAlphaForTransparancyBinning() << std::endl;
375
376                document.setReadObjectRecordData(options->getOptionString().find("readObjectRecordData")==std::string::npos);
377                OSG_DEBUG << readerMsg << "readObjectRecordData=" << !document.getReadObjectRecordData() << std::endl;
378
379                document.setDoUnitsConversion((options->getOptionString().find("noUnitsConversion")==std::string::npos)); // default to true, unless noUnitsConversion is specified.
380                OSG_DEBUG << readerMsg << "noUnitsConversion=" << !document.getDoUnitsConversion() << std::endl;
381
382                if (document.getDoUnitsConversion())
383                {
384                    if (options->getOptionString().find("convertToFeet")!=std::string::npos)
385                        document.setDesiredUnits(FEET);
386                    else if (options->getOptionString().find("convertToInches")!=std::string::npos)
387                        document.setDesiredUnits(INCHES);
388                    else if (options->getOptionString().find("convertToMeters")!=std::string::npos)
389                        document.setDesiredUnits(METERS);
390                    else if (options->getOptionString().find("convertToKilometers")!=std::string::npos)
391                        document.setDesiredUnits(KILOMETERS);
392                    else if (options->getOptionString().find("convertToNauticalMiles")!=std::string::npos)
393                        document.setDesiredUnits(NAUTICAL_MILES);
394                }
395
396                const ParentPools* pools = dynamic_cast<const ParentPools*>( options->getUserData() );
397                if (pools)
398                {
399                    // This file is an external reference. The individual pools will
400                    // be non-NULL if the parent is overriding the ext ref model's pools.
401                    if (pools->getColorPool())
402                        document.setColorPool( pools->getColorPool(), true );
403                    if (pools->getTexturePool())
404                        document.setTexturePool( pools->getTexturePool(), true );
405                    if (pools->getMaterialPool())
406                        document.setMaterialPool( pools->getMaterialPool(), true );
407                    if (pools->getLightSourcePool())
408                        document.setLightSourcePool( pools->getLightSourcePool(), true );
409                    if (pools->getLPAppearancePool())
410                        document.setLightPointAppearancePool( pools->getLPAppearancePool(), true );
411                    if (pools->getLPAnimationPool())
412                        document.setLightPointAnimationPool( pools->getLPAnimationPool(), true );
413                    if (pools->getShaderPool())
414                        document.setShaderPool( pools->getShaderPool(), true );
415                }
416            }
417
418            const int RECORD_HEADER_SIZE = 4;
419            opcode_type continuationOpcode = INVALID_OP;
420            std::string continuationBuffer;
421
422            while (fin.good() && !document.done())
423            {
424                // The continuation record complicates things a bit.
425
426                // Get current read position in stream.
427                std::istream::pos_type pos = fin.tellg();
428
429                // get opcode and size
430                flt::DataInputStream dataStream(fin.rdbuf());
431                opcode_type opcode = (opcode_type)dataStream.readUInt16();
432                size_type   size   = (size_type)dataStream.readUInt16();
433
434                // If size == 0, an EOF has probably been reached, i.e. there is nothing
435                // more to read so we must return.
436                if (size==0)
437                {
438                    // If a header was read, we return it.
439                    // This allows us handle files with empty hierarchies.
440                    if (document.getHeaderNode())
441                    {
442                        return document.getHeaderNode();
443                    }
444                    else // (no valid header)
445                    {
446                        return ReadResult::ERROR_IN_READING_FILE;
447                    }
448                }
449
450                // variable length record complete?
451                if (!continuationBuffer.empty() && opcode!=CONTINUATION_OP)
452                {
453                    // parse variable length record
454                    std::stringbuf sb(continuationBuffer);
455                    flt::RecordInputStream recordStream(&sb);
456                    recordStream.readRecordBody(continuationOpcode, continuationBuffer.length(), document);
457
458                    continuationOpcode = INVALID_OP;
459                    continuationBuffer.clear();
460                }
461
462                // variable length record use continuation buffer in case next
463                // record is a continuation record.
464                if (opcode==EXTENSION_OP ||
465                    opcode==NAME_TABLE_OP ||
466                    opcode==LOCAL_VERTEX_POOL_OP ||
467                    opcode==MESH_PRIMITIVE_OP)
468                {
469                    continuationOpcode = opcode;
470
471                    if (size > RECORD_HEADER_SIZE)
472                    {
473                        // Put record in buffer.
474                        std::string buffer((std::string::size_type)size-RECORD_HEADER_SIZE,'\0');
475                        fin.read(&buffer[0], size-RECORD_HEADER_SIZE);
476
477                        // Can't parse it until we know we have the complete record.
478                        continuationBuffer = buffer;
479                    }
480                }
481                else if (opcode==CONTINUATION_OP)
482                {
483                    if (size > RECORD_HEADER_SIZE)
484                    {
485                        std::string buffer((std::string::size_type)size-RECORD_HEADER_SIZE,'\0');
486                        fin.read(&buffer[0], size-RECORD_HEADER_SIZE);
487
488                        // The record continues.
489                        continuationBuffer.append(buffer);
490                    }
491                }
492                else if (opcode==VERTEX_PALETTE_OP)
493                {
494                    // Vertex Palette needs the file stream as it reads beyond the current record.
495                    flt::RecordInputStream recordStream(fin.rdbuf());
496                    recordStream.readRecordBody(opcode, size, document);
497                }
498                else // normal (fixed size) record.
499                {
500                    // Put record in buffer.
501                    std::string buffer((std::string::size_type)size,'\0');
502                    if (size > RECORD_HEADER_SIZE)
503                        fin.read(&buffer[0], size-RECORD_HEADER_SIZE);
504
505                    // Parse buffer.
506                    std::stringbuf sb(buffer);
507                    flt::RecordInputStream recordStream(&sb);
508                    recordStream.readRecordBody(opcode, size, document);
509                }
510            }
511
512            if (!document.getHeaderNode())
513                return ReadResult::ERROR_IN_READING_FILE;
514
515            if (!document.getPreserveFace())
516            {
517                osgUtil::Optimizer optimizer;
518                optimizer.optimize(document.getHeaderNode(),
519                    osgUtil::Optimizer::SHARE_DUPLICATE_STATE |
520                    osgUtil::Optimizer::MERGE_GEOMETRY |
521                    osgUtil::Optimizer::MERGE_GEODES |
522                    osgUtil::Optimizer::TESSELLATE_GEOMETRY |
523                    osgUtil::Optimizer::STATIC_OBJECT_DETECTION);
524            }
525
526            return document.getHeaderNode();
527        }
528
529        virtual WriteResult writeObject(const Object& object,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
530        {
531            const Node* node = dynamic_cast<const Node*>(&object);
532            if (node) return writeNode( *node, fileName, options );
533            return WriteResult::FILE_NOT_HANDLED;
534        }
535
536        virtual WriteResult writeNode( const osg::Node& node, const std::string& fileName, const Options* options ) const
537        {
538            if ( fileName.empty() )
539            {
540                return WriteResult::FILE_NOT_HANDLED;
541            }
542
543            std::string ext = osgDB::getLowerCaseFileExtension( fileName );
544            if ( !acceptsExtension(ext) )
545                return WriteResult::FILE_NOT_HANDLED;
546
547            // Get and save the implicit path name (in case a path wasn't specified in Options).
548            std::string filePath = osgDB::getFilePath( fileName );
549            if (!filePath.empty())
550                _implicitPath = filePath;
551
552            osgDB::ofstream fOut;
553            fOut.open( fileName.c_str(), std::ios::out | std::ios::binary );
554            if ( fOut.fail())
555            {
556                OSG_FATAL << "fltexp: Failed to open output stream." << std::endl;
557                return WriteResult::ERROR_IN_WRITING_FILE;
558            }
559
560            WriteResult wr = WriteResult::FILE_NOT_HANDLED;
561            wr = writeNode( node, fOut, options );
562            fOut.close();
563
564            return wr;
565        }
566
567
568        virtual WriteResult writeObject(const Object& object,std::ostream& fout, const osgDB::ReaderWriter::Options* options) const
569        {
570            const Node* node = dynamic_cast<const Node*>(&object);
571            if (node) return writeNode( *node, fout, options );
572            return WriteResult::FILE_NOT_HANDLED;
573        }
574
575        virtual WriteResult writeNode( const osg::Node& node, std::ostream& fOut, const Options* options ) const
576        {
577            // Convert Options to FltOptions.
578            ExportOptions* fltOpt = new ExportOptions( options );
579            fltOpt->parseOptionsString();
580
581            // If user didn't specify a temp dir, use the output directory
582            //   that was implicit in the output file name.
583            if (fltOpt->getTempDir().empty())
584                fltOpt->setTempDir( _implicitPath );
585            if (!fltOpt->getTempDir().empty())
586            {
587                // If the temp directory doesn't already exist, make it.
588                if ( !osgDB::makeDirectory( fltOpt->getTempDir() ) )
589                {
590                    OSG_FATAL << "fltexp: Error creating temp dir: " << fltOpt->getTempDir() << std::endl;
591                    return WriteResult::ERROR_IN_WRITING_FILE;
592                }
593            }
594
595            flt::DataOutputStream dos( fOut.rdbuf(), fltOpt->getValidateOnly() );
596            flt::FltExportVisitor fnv( &dos, fltOpt );
597
598            // Hm. 'node' is const, but in order to write out this scene graph,
599            //   must use Node::accept() which requires 'node' to be non-const.
600            //   Pretty much requires casting away const.
601            osg::Node* nodeNonConst = const_cast<osg::Node*>( &node );
602            if (!nodeNonConst)
603                return WriteResult::ERROR_IN_WRITING_FILE;
604            nodeNonConst->accept( fnv );
605            fnv.complete( node );
606
607            return fltOpt->getWriteResult();
608        }
609
610    protected:
611        mutable std::string _implicitPath;
612
613        mutable OpenThreads::ReentrantMutex _serializerMutex;
614};
615
616// now register with Registry to instantiate the above
617// reader/writer.
618REGISTER_OSGPLUGIN(OpenFlight, FLTReaderWriter)
Note: See TracBrowser for help on using the browser.