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

Revision 13041, 26.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++-*- 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 opcode and size
427                flt::DataInputStream dataStream(fin.rdbuf());
428                opcode_type opcode = (opcode_type)dataStream.readUInt16();
429                size_type   size   = (size_type)dataStream.readUInt16();
430
431                // If size == 0, an EOF has probably been reached, i.e. there is nothing
432                // more to read so we must return.
433                if (size==0)
434                {
435                    // If a header was read, we return it.
436                    // This allows us handle files with empty hierarchies.
437                    if (document.getHeaderNode())
438                    {
439                        return document.getHeaderNode();
440                    }
441                    else // (no valid header)
442                    {
443                        return ReadResult::ERROR_IN_READING_FILE;
444                    }
445                }
446
447                // variable length record complete?
448                if (!continuationBuffer.empty() && opcode!=CONTINUATION_OP)
449                {
450                    // parse variable length record
451                    std::stringbuf sb(continuationBuffer);
452                    flt::RecordInputStream recordStream(&sb);
453                    recordStream.readRecordBody(continuationOpcode, continuationBuffer.length(), document);
454
455                    continuationOpcode = INVALID_OP;
456                    continuationBuffer.clear();
457                }
458
459                // variable length record use continuation buffer in case next
460                // record is a continuation record.
461                if (opcode==EXTENSION_OP ||
462                    opcode==NAME_TABLE_OP ||
463                    opcode==LOCAL_VERTEX_POOL_OP ||
464                    opcode==MESH_PRIMITIVE_OP)
465                {
466                    continuationOpcode = opcode;
467
468                    if (size > RECORD_HEADER_SIZE)
469                    {
470                        // Put record in buffer.
471                        std::string buffer((std::string::size_type)size-RECORD_HEADER_SIZE,'\0');
472                        fin.read(&buffer[0], size-RECORD_HEADER_SIZE);
473
474                        // Can't parse it until we know we have the complete record.
475                        continuationBuffer = buffer;
476                    }
477                }
478                else if (opcode==CONTINUATION_OP)
479                {
480                    if (size > RECORD_HEADER_SIZE)
481                    {
482                        std::string buffer((std::string::size_type)size-RECORD_HEADER_SIZE,'\0');
483                        fin.read(&buffer[0], size-RECORD_HEADER_SIZE);
484
485                        // The record continues.
486                        continuationBuffer.append(buffer);
487                    }
488                }
489                else if (opcode==VERTEX_PALETTE_OP)
490                {
491                    // Vertex Palette needs the file stream as it reads beyond the current record.
492                    flt::RecordInputStream recordStream(fin.rdbuf());
493                    recordStream.readRecordBody(opcode, size, document);
494                }
495                else // normal (fixed size) record.
496                {
497                    // Put record in buffer.
498                    std::string buffer((std::string::size_type)size,'\0');
499                    if (size > RECORD_HEADER_SIZE)
500                        fin.read(&buffer[0], size-RECORD_HEADER_SIZE);
501
502                    // Parse buffer.
503                    std::stringbuf sb(buffer);
504                    flt::RecordInputStream recordStream(&sb);
505                    recordStream.readRecordBody(opcode, size, document);
506                }
507            }
508
509            if (!document.getHeaderNode())
510                return ReadResult::ERROR_IN_READING_FILE;
511
512            if (!document.getPreserveFace())
513            {
514                osgUtil::Optimizer optimizer;
515                optimizer.optimize(document.getHeaderNode(),
516                    osgUtil::Optimizer::SHARE_DUPLICATE_STATE |
517                    osgUtil::Optimizer::MERGE_GEOMETRY |
518                    osgUtil::Optimizer::MERGE_GEODES |
519                    osgUtil::Optimizer::TESSELLATE_GEOMETRY |
520                    osgUtil::Optimizer::STATIC_OBJECT_DETECTION);
521            }
522
523            return document.getHeaderNode();
524        }
525
526        virtual WriteResult writeObject(const Object& object,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
527        {
528            const Node* node = dynamic_cast<const Node*>(&object);
529            if (node) return writeNode( *node, fileName, options );
530            return WriteResult::FILE_NOT_HANDLED;
531        }
532
533        virtual WriteResult writeNode( const osg::Node& node, const std::string& fileName, const Options* options ) const
534        {
535            if ( fileName.empty() )
536            {
537                return WriteResult::FILE_NOT_HANDLED;
538            }
539
540            std::string ext = osgDB::getLowerCaseFileExtension( fileName );
541            if ( !acceptsExtension(ext) )
542                return WriteResult::FILE_NOT_HANDLED;
543
544            // Get and save the implicit path name (in case a path wasn't specified in Options).
545            std::string filePath = osgDB::getFilePath( fileName );
546            if (!filePath.empty())
547                _implicitPath = filePath;
548
549            osgDB::ofstream fOut;
550            fOut.open( fileName.c_str(), std::ios::out | std::ios::binary );
551            if ( fOut.fail())
552            {
553                OSG_FATAL << "fltexp: Failed to open output stream." << std::endl;
554                return WriteResult::ERROR_IN_WRITING_FILE;
555            }
556
557            WriteResult wr = WriteResult::FILE_NOT_HANDLED;
558            wr = writeNode( node, fOut, options );
559            fOut.close();
560
561            return wr;
562        }
563
564
565        virtual WriteResult writeObject(const Object& object,std::ostream& fout, const osgDB::ReaderWriter::Options* options) const
566        {
567            const Node* node = dynamic_cast<const Node*>(&object);
568            if (node) return writeNode( *node, fout, options );
569            return WriteResult::FILE_NOT_HANDLED;
570        }
571
572        virtual WriteResult writeNode( const osg::Node& node, std::ostream& fOut, const Options* options ) const
573        {
574            // Convert Options to FltOptions.
575            ExportOptions* fltOpt = new ExportOptions( options );
576            fltOpt->parseOptionsString();
577
578            // If user didn't specify a temp dir, use the output directory
579            //   that was implicit in the output file name.
580            if (fltOpt->getTempDir().empty())
581                fltOpt->setTempDir( _implicitPath );
582            if (!fltOpt->getTempDir().empty())
583            {
584                // If the temp directory doesn't already exist, make it.
585                if ( !osgDB::makeDirectory( fltOpt->getTempDir() ) )
586                {
587                    OSG_FATAL << "fltexp: Error creating temp dir: " << fltOpt->getTempDir() << std::endl;
588                    return WriteResult::ERROR_IN_WRITING_FILE;
589                }
590            }
591
592            flt::DataOutputStream dos( fOut.rdbuf(), fltOpt->getValidateOnly() );
593            flt::FltExportVisitor fnv( &dos, fltOpt );
594
595            // Hm. 'node' is const, but in order to write out this scene graph,
596            //   must use Node::accept() which requires 'node' to be non-const.
597            //   Pretty much requires casting away const.
598            osg::Node* nodeNonConst = const_cast<osg::Node*>( &node );
599            if (!nodeNonConst)
600                return WriteResult::ERROR_IN_WRITING_FILE;
601            nodeNonConst->accept( fnv );
602            fnv.complete( node );
603
604            return fltOpt->getWriteResult();
605        }
606
607    protected:
608        mutable std::string _implicitPath;
609
610        mutable OpenThreads::ReentrantMutex _serializerMutex;
611};
612
613// now register with Registry to instantiate the above
614// reader/writer.
615REGISTER_OSGPLUGIN(OpenFlight, FLTReaderWriter)
Note: See TracBrowser for help on using the browser.