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

Revision 10283, 27.0 kB (checked in by robert, 5 years ago)

From Gregory Jaegy and Robert Osfield, added support for static linking of OpenFlight? plugin

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[7748]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
[5038]14//
[7748]15// OpenFlight® loader for OpenSceneGraph
[5038]16//
[7669]17//  Copyright (C) 2005-2007  Brede Johansen
[5038]18//
19
20#include <stdexcept>
21#include <osg/Notify>
[5136]22#include <osg/ProxyNode>
[5038]23#include <osgDB/FileNameUtils>
24#include <osgDB/FileUtils>
25#include <osgDB/Registry>
26#include <osgDB/ReadFile>
[6267]27#include <OpenThreads/ReentrantMutex>
[5218]28#include <osgUtil/Optimizer>
[5038]29
30#include "Registry.h"
31#include "Document.h"
32#include "RecordInputStream.h"
[8003]33#include "DataOutputStream.h"
34#include "FltExportVisitor.h"
35#include "ExportOptions.h"
[5038]36
[6267]37#define SERIALIZER() OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_serializerMutex) 
[5038]38
39using namespace flt;
40using namespace osg;
41using namespace osgDB;
42
[10283]43// pull in symbols from attr plugin
44USE_OSGPLUGIN(attr)
[5038]45
[10283]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
[5136]148class ReadExternalsVisitor : public osg::NodeVisitor
149{
[5886]150    osg::ref_ptr<ReaderWriter::Options> _options;
[5820]151    bool _cloneExternalReferences;
[5136]152
153public:
154
155    ReadExternalsVisitor(ReaderWriter::Options* options) :
156        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
[5820]157        _options(options),
158        _cloneExternalReferences(false)
[5136]159    {
[5820]160        if (options)
161            _cloneExternalReferences = (options->getOptionString().find("cloneExternalReferences")!=std::string::npos);
[5136]162    }
[5820]163
[5136]164    virtual ~ReadExternalsVisitor() {}
165
166    virtual void apply(ProxyNode& node)
167    {
[5281]168        // Transfer ownership of pools.
[5236]169        _options->setUserData( node.getUserData() );
[5281]170        node.setUserData(NULL);
[5236]171
[5136]172        for (unsigned int pos=0; pos<node.getNumFileNames(); pos++)
173        {
174            std::string filename = node.getFileName(pos);
175
176            // read external
[5820]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            }
[5136]185        }
186    }
187};
188
189
[5820]190
[8003]191/*!
192
[8564]193FLTReaderWriter supports importing and exporting OSG scene graphs
[8003]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
[5038]222class FLTReaderWriter : public ReaderWriter
223{
224    public:
[8003]225        FLTReaderWriter()
226          : _implicitPath( "." )
[8578]227        {
228            supportsExtension("flt","OpenFlight format");
229           
[8596]230            supportsOption("clampToEdge","Import option");
231            supportsOption("keepExternalReferences","Import option");
232            supportsOption("preserveFace","Import option");
233            supportsOption("preserveObject","Import option");
234            supportsOption("dofAnimation","Import option");
235            supportsOption("billboardCenter","Import option");
236            supportsOption("noTextureAlphaForTransparancyBinning","Import option");
237            supportsOption("readObjectRecordData","Import option");
238            supportsOption("noUnitsConversion","Import option");
239            supportsOption("convertToFeet","Import option");
240            supportsOption("convertToInches","Import option");
241            supportsOption("convertToMeters","Import option");
242            supportsOption("convertToKilometers","Import option");
243            supportsOption("convertToNauticalMiles","Import option");
[8595]244
[8596]245            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\"." );
246            supportsOption( "units=<units>", "Export option: Specifies the contents of the Units field of the OpenFliht header record. Valid values include INCHES, FEET, METERS, KILOMETERS, and NATICAL_MILES. Default is METERS. Example: \"units=METERS\"." );
247            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." );
248            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\"." );
249            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\"." );
250            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." );
[8578]251        }
[8003]252
[5038]253        virtual const char* className() const { return "FLT Reader/Writer"; }
254
255        virtual bool acceptsExtension(const std::string& extension) const
256        {
[7169]257            return equalCaseInsensitive(extension,"flt") || extension.empty();
[5038]258        }
259
260        virtual ReadResult readObject(const std::string& file, const Options* options) const
261        {
262            return readNode(file, options);
263        }
264       
265        virtual ReadResult readNode(const std::string& file, const Options* options) const
266        {
267            SERIALIZER();
268
269            std::string ext = osgDB::getLowerCaseFileExtension(file);
270            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
271
[5136]272            std::string fileName = osgDB::findDataFile(file, options);
[5038]273            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
274
[5136]275            // in local cache?
276            {
[5986]277                osg::Node* node = flt::Registry::instance()->getExternalFromLocalCache(fileName);
[5136]278                if (node)
279                    return ReadResult(node, ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE);
280            }
281
282            // setting up the database path so that internally referenced file are searched for on relative paths.
[5038]283            osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
284            local_opt->setDatabasePath(osgDB::getFilePath(fileName));
[5122]285
[5136]286            ReadResult rr;
[5122]287
[5136]288            // read file
289            {
[9124]290                osgDB::ifstream istream;
[5136]291                istream.imbue(std::locale::classic());
292                istream.open(fileName.c_str(), std::ios::in | std::ios::binary);
293
294                if (istream)
295                {
296                    rr = readNode(istream,local_opt.get());
297                }
298            }
299
300            static int nestedExternalsLevel = 0;
301            if (rr.success())
302            {
303                // add to local cache.
[5986]304                flt::Registry::instance()->addExternalToLocalCache(fileName,rr.getNode());
[5461]305       
306                bool keepExternalReferences = false;
307                if (options)
308                    keepExternalReferences = (options->getOptionString().find("keepExternalReferences")!=std::string::npos);
[5136]309
[5461]310
311                if ( !keepExternalReferences )
[5136]312                {
[5461]313                    osg::notify(osg::DEBUG_INFO) << "keepExternalReferences not found, so externals will be re-readed"<<std::endl;
314                    // read externals.
315                    if (rr.getNode())
316                    {
317                        nestedExternalsLevel++;
318                        ReadExternalsVisitor visitor(local_opt.get());
319                        rr.getNode()->accept(visitor);
320                        nestedExternalsLevel--;
321                    }
[5136]322                }
[5461]323                else
324                {
325                    osg::notify(osg::DEBUG_INFO) << "keepExternalReferences found, so externals will be left as ProxyNodes"<<std::endl;   
326                }
[5136]327            }
328
329            // clear local cache.
330            if (nestedExternalsLevel==0)
331                flt::Registry::instance()->clearLocalCache();
332
333            return rr;
[5038]334        }
335       
336        virtual ReadResult readObject(std::istream& fin, const Options* options) const
337        {
338            return readNode(fin, options);
339        }
340       
341        virtual ReadResult readNode(std::istream& fin, const Options* options) const
342        {
[5136]343            Document document;
344            document.setOptions(options);
345
[5236]346            // option string and parent pools
[5136]347            if (options)
[5038]348            {
[5205]349                const char readerMsg[] = "flt reader option: ";
[5461]350               
[5794]351                document.setReplaceClampWithClampToEdge((options->getOptionString().find("clampToEdge")!=std::string::npos));
352                osg::notify(osg::DEBUG_INFO) << readerMsg << "clampToEdge=" << document.getReplaceClampWithClampToEdge() << std::endl;
353
[5461]354                document.setKeepExternalReferences((options->getOptionString().find("keepExternalReferences")!=std::string::npos));
355                osg::notify(osg::DEBUG_INFO) << readerMsg << "keepExternalReferences=" << document.getKeepExternalReferences() << std::endl;
[5205]356
[5238]357                document.setPreserveFace((options->getOptionString().find("preserveFace")!=std::string::npos));
358                osg::notify(osg::DEBUG_INFO) << readerMsg << "preserveFace=" << document.getPreserveFace() << std::endl;
[5205]359
[5528]360                document.setPreserveObject((options->getOptionString().find("preserveObject")!=std::string::npos));
361                osg::notify(osg::DEBUG_INFO) << readerMsg << "preserveObject=" << document.getPreserveObject() << std::endl;
362
[5205]363                document.setDefaultDOFAnimationState((options->getOptionString().find("dofAnimation")!=std::string::npos));
364                osg::notify(osg::DEBUG_INFO) << readerMsg << "dofAnimation=" << document.getDefaultDOFAnimationState() << std::endl;
365
[5610]366                document.setUseBillboardCenter((options->getOptionString().find("billboardCenter")!=std::string::npos));
367                osg::notify(osg::DEBUG_INFO) << readerMsg << "billboardCenter=" << document.getUseBillboardCenter() << std::endl;
368
[5136]369                document.setUseTextureAlphaForTransparancyBinning(options->getOptionString().find("noTextureAlphaForTransparancyBinning")==std::string::npos);
[5610]370                osg::notify(osg::DEBUG_INFO) << readerMsg << "noTextureAlphaForTransparancyBinning=" << !document.getUseTextureAlphaForTransparancyBinning() << std::endl;
[5038]371
[7931]372                document.setReadObjectRecordData(options->getOptionString().find("readObjectRecordData")==std::string::npos);
373                osg::notify(osg::DEBUG_INFO) << readerMsg << "readObjectRecordData=" << !document.getReadObjectRecordData() << std::endl;
374
[5205]375                document.setDoUnitsConversion((options->getOptionString().find("noUnitsConversion")==std::string::npos)); // default to true, unless noUnitsConversion is specified.
[5610]376                osg::notify(osg::DEBUG_INFO) << readerMsg << "noUnitsConversion=" << !document.getDoUnitsConversion() << std::endl;
[5205]377
[5136]378                if (document.getDoUnitsConversion())
[5038]379                {
[5136]380                    if (options->getOptionString().find("convertToFeet")!=std::string::npos)
381                        document.setDesiredUnits(FEET);
382                    else if (options->getOptionString().find("convertToInches")!=std::string::npos)
383                        document.setDesiredUnits(INCHES);
384                    else if (options->getOptionString().find("convertToMeters")!=std::string::npos)
385                        document.setDesiredUnits(METERS);
386                    else if (options->getOptionString().find("convertToKilometers")!=std::string::npos)
387                        document.setDesiredUnits(KILOMETERS);
388                    else if (options->getOptionString().find("convertToNauticalMiles")!=std::string::npos)
389                        document.setDesiredUnits(NAUTICAL_MILES);
[5038]390                }
[5236]391
392                const ParentPools* pools = dynamic_cast<const ParentPools*>( options->getUserData() );
393                if (pools)
394                {
395                    // This file is an external reference. The individual pools will
396                    // be non-NULL if the parent is overriding the ext ref model's pools.
397                    if (pools->getColorPool())
398                        document.setColorPool( pools->getColorPool(), true );
399                    if (pools->getTexturePool())
400                        document.setTexturePool( pools->getTexturePool(), true );
401                    if (pools->getMaterialPool())
402                        document.setMaterialPool( pools->getMaterialPool(), true );
[6091]403                    if (pools->getLightSourcePool())
404                        document.setLightSourcePool( pools->getLightSourcePool(), true );
[5236]405                    if (pools->getLPAppearancePool())
406                        document.setLightPointAppearancePool( pools->getLPAppearancePool(), true );
[6759]407                    if (pools->getLPAnimationPool())
408                        document.setLightPointAnimationPool( pools->getLPAnimationPool(), true );
[5236]409                    if (pools->getShaderPool())
410                        document.setShaderPool( pools->getShaderPool(), true );
411                }
[5136]412            }
[5038]413
[7669]414            const int RECORD_HEADER_SIZE = 4;
[8564]415            opcode_type continuationOpcode = INVALID_OP;
[7669]416            std::string continuationBuffer;
417
418            while (fin.good() && !document.done())
[5136]419            {
[7669]420                // The continuation record complicates things a bit.
421
422                // Get current read position in stream.
423                std::istream::pos_type pos = fin.tellg();
424
425                // get opcode and size
426                flt::DataInputStream dataStream(fin.rdbuf());
427                opcode_type opcode = (opcode_type)dataStream.readUInt16();
428                size_type   size   = (size_type)dataStream.readUInt16();
429
[8564]430                // If size == 0, an EOF has probably been reached, i.e. there is nothing
431                // more to read so we must return.
[8295]432                if (size==0)
[8564]433                {
434                    // If a header was read, we return it.
435                    // This allows us handle files with empty hierarchies.
436                    if (document.getHeaderNode())
437                    {
438                        return document.getHeaderNode();
439                    }
440                    else // (no valid header)
441                    {
442                        return ReadResult::ERROR_IN_READING_FILE;
443                    }
444                }
[8295]445
[7669]446                // variable length record complete?
447                if (!continuationBuffer.empty() && opcode!=CONTINUATION_OP)
[5038]448                {
[7669]449                    // parse variable length record
450                    std::stringbuf sb(continuationBuffer);
451                    flt::RecordInputStream recordStream(&sb);
452                    recordStream.readRecordBody(continuationOpcode, continuationBuffer.length(), document);
453
[8564]454                    continuationOpcode = INVALID_OP;
[7669]455                    continuationBuffer.clear();
[5038]456                }
[7669]457
458                // variable length record use continuation buffer in case next
459                // record is a continuation record.
460                if (opcode==EXTENSION_OP ||
461                    opcode==NAME_TABLE_OP ||
462                    opcode==LOCAL_VERTEX_POOL_OP ||
463                    opcode==MESH_PRIMITIVE_OP)
464                {
465                    continuationOpcode = opcode;
466
467                    if (size > RECORD_HEADER_SIZE)
468                    {
469                        // Put record in buffer.
470                        std::string buffer((std::string::size_type)size-RECORD_HEADER_SIZE,'\0');
471                        fin.read(&buffer[0], size-RECORD_HEADER_SIZE);
472
473                        // Can't parse it until we know we have the complete record.
474                        continuationBuffer = buffer;
475                    }
476                }
477                else if (opcode==CONTINUATION_OP)
478                {
479                    if (size > RECORD_HEADER_SIZE)
480                    {
481                        std::string buffer((std::string::size_type)size-RECORD_HEADER_SIZE,'\0');
482                        fin.read(&buffer[0], size-RECORD_HEADER_SIZE);
483
484                        // The record continues.
485                        continuationBuffer.append(buffer);
486                    }
487                }
488                else if (opcode==VERTEX_PALETTE_OP)
489                {
490                    // Vertex Palette needs the file stream as it reads beyond the current record.
491                    flt::RecordInputStream recordStream(fin.rdbuf());
492                    recordStream.readRecordBody(opcode, size, document);
493                }
494                else // normal (fixed size) record.
495                {
496                    // Put record in buffer.
497                    std::string buffer((std::string::size_type)size,'\0');
498                    if (size > RECORD_HEADER_SIZE)
499                        fin.read(&buffer[0], size-RECORD_HEADER_SIZE);
500
501                    // Parse buffer.
502                    std::stringbuf sb(buffer);
503                    flt::RecordInputStream recordStream(&sb);
504                    recordStream.readRecordBody(opcode, size, document);
505                }
[5136]506            }
[5038]507
[5136]508            if (!document.getHeaderNode())
509                return ReadResult::ERROR_IN_READING_FILE;
[5461]510
[5218]511            if (!document.getPreserveFace())
512            {
513                osgUtil::Optimizer optimizer;
[6257]514                optimizer.optimize(document.getHeaderNode(),
515                    osgUtil::Optimizer::SHARE_DUPLICATE_STATE |
516                    osgUtil::Optimizer::MERGE_GEOMETRY |
517                    osgUtil::Optimizer::MERGE_GEODES |
518                    osgUtil::Optimizer::TESSELLATE_GEOMETRY |
519                    osgUtil::Optimizer::STATIC_OBJECT_DETECTION);
[5218]520            }
[5038]521
[5136]522            return document.getHeaderNode();
[5038]523        }
524
525        virtual WriteResult writeObject(const Object& object,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
526        {
527            const Node* node = dynamic_cast<const Node*>(&object);
528            if (node) return writeNode( *node, fileName, options );
529            return WriteResult::FILE_NOT_HANDLED;
530        }
531
[8003]532        virtual WriteResult writeNode( const osg::Node& node, const std::string& fileName, const Options* options ) const
[5038]533        {
[8003]534            if ( fileName.empty() )
535            {
536                return WriteResult::FILE_NOT_HANDLED;
537            }
[9890]538
[8003]539            std::string ext = osgDB::getLowerCaseFileExtension( fileName );
540            if ( !acceptsExtension(ext) )
541                return WriteResult::FILE_NOT_HANDLED;
542
543            // Get and save the implicit path name (in case a path wasn't specified in Options).
544            std::string filePath = osgDB::getFilePath( fileName );
545            if (!filePath.empty())
546                _implicitPath = filePath;
547
[9124]548            osgDB::ofstream fOut;
[8003]549            fOut.open( fileName.c_str(), std::ios::out | std::ios::binary );
550            if ( fOut.fail())
551            {
552                osg::notify( osg::FATAL ) << "fltexp: Failed to open output stream." << std::endl;
553                return WriteResult::ERROR_IN_WRITING_FILE;
554            }
555
556            WriteResult wr = WriteResult::FILE_NOT_HANDLED;
557            wr = writeNode( node, fOut, options );
558            fOut.close();
559
560            return wr;
[5038]561        }
[8003]562
563
[5038]564        virtual WriteResult writeObject(const Object& object,std::ostream& fout, const osgDB::ReaderWriter::Options* options) const
565        {
566            const Node* node = dynamic_cast<const Node*>(&object);
567            if (node) return writeNode( *node, fout, options );
568            return WriteResult::FILE_NOT_HANDLED;
569        }
570
[8003]571        virtual WriteResult writeNode( const osg::Node& node, std::ostream& fOut, const Options* options ) const
[5038]572        {
[8003]573            // Convert Options to FltOptions.
574            ExportOptions* fltOpt = new ExportOptions( options );
575            fltOpt->parseOptionsString();
576
577            // If user didn't specify a temp dir, use the output directory
578            //   that was implicit in the output file name.
579            if (fltOpt->getTempDir().empty())
580                fltOpt->setTempDir( _implicitPath );
581            if (!fltOpt->getTempDir().empty())
582            {
583                // If the temp directory doesn't already exist, make it.
584                if ( !osgDB::makeDirectory( fltOpt->getTempDir() ) )
585                {
586                    osg::notify( osg::FATAL ) << "fltexp: Error creating temp dir: " << fltOpt->getTempDir() << std::endl;
587                    return WriteResult::ERROR_IN_WRITING_FILE;
588                }
589            }
590
591            flt::DataOutputStream dos( fOut.rdbuf(), fltOpt->getValidateOnly() );
592            flt::FltExportVisitor fnv( &dos, fltOpt );
593
594            // Hm. 'node' is const, but in order to write out this scene graph,
595            //   must use Node::accept() which requires 'node' to be non-const.
596            //   Pretty much requires casting away const.
597            osg::Node* nodeNonConst = const_cast<osg::Node*>( &node );
[8010]598            if (!nodeNonConst)
599                return WriteResult::ERROR_IN_WRITING_FILE;
[8003]600            nodeNonConst->accept( fnv );
601            fnv.complete( node );
602
[8010]603            return fltOpt->getWriteResult();
[5038]604        }
605
606    protected:
[8003]607        mutable std::string _implicitPath;
[5038]608
[6267]609        mutable OpenThreads::ReentrantMutex _serializerMutex;
[5038]610};
611
612// now register with Registry to instantiate the above
613// reader/writer.
[7076]614REGISTER_OSGPLUGIN(OpenFlight, FLTReaderWriter)
Note: See TracBrowser for help on using the browser.