root/OpenSceneGraph/trunk/src/osgPlugins/OpenFlight/expPrimaryRecords.cpp @ 9581

Revision 9581, 27.2 kB (checked in by robert, 6 years ago)

Replaced -1 with ~0u to fix warning due to being written to a UInt field. Note, OpenFlight? spec says -1, which is clearly an error in the spec, so we've had to guess at ~0u being an appropriate value.

RevLine 
[8003]1/*
2 * This library is open source and may be redistributed and/or modified under
3 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at
4 * your option) any later version. The full license is in the LICENSE file
5 * included with this distribution, and on the openscenegraph.org website.
6 *
7 * This library is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * OpenSceneGraph Public License for more details.
11*/
12
13//
14// Copyright(c) 2008 Skew Matrix Software LLC.
15//
16
17#include "FltExportVisitor.h"
18#include "ExportOptions.h"
19#include "VertexPaletteManager.h"
20#include "LightSourcePaletteManager.h"
21#include "DataOutputStream.h"
22#include "Opcodes.h"
23#include <osg/Group>
24#include <osg/Sequence>
25#include <osg/LightSource>
26#include <osg/LOD>
27#include <osg/ProxyNode>
28#include <osg/Switch>
29#include <osgSim/MultiSwitch>
30#include <osgSim/DOFTransform>
31#include <osgSim/LightPointNode>
32#include <osgSim/ObjectRecordData>
33
34
35// FIXME: This header was copied verbatim from the importer, with the only change
36// being that the symbols it defines are placed in namespace 'fltexp' instead
37// of 'flt'.  Thus, this one-off copy has to be kept in sync with the
38// importer until the reader/writer are unified...
39#include "Pools.h"
40
41
42namespace flt
43{
44
45
46void
47FltExportVisitor::writeHeader( const std::string& headerName )
48{
49    int16 length;
50    int32 version;
51    const int ver = _fltOpt->getFlightFileVersionNumber();
52    if (ver == ExportOptions::VERSION_15_7)
53    {
54        length = 304;
55        version = 1570;
56    }
57    else if (ver == ExportOptions::VERSION_15_8)
58    {
59        length = 324;
60        version = 1580;
61    }
62    else // ExportOptions::VERSION_16_1:
63    {
64        length = 324;
65        version = 1610;
66    }
67
68    int8 units;
69    switch( _fltOpt->getFlightUnits() )
70    {
71    case ExportOptions::KILOMETERS:
72        units = 1;
73        break;
74    case ExportOptions::FEET:
75        units = 4;
76        break;
77    case ExportOptions::INCHES:
78        units = 5;
79        break;
80    case ExportOptions::NAUTICAL_MILES:
81        units = 8;
82        break;
83    default:
84    case ExportOptions::METERS:
85        units = 0;
86        break;
87    }
88
89    static const unsigned int SAVE_VERTEX_NORMALS_BIT = 0x80000000u >> 0;
[9382]90    //static const unsigned int PACKED_COLOR_MODE_BIT   = 0x80000000u >> 1;
91    //static const unsigned int CAD_VIEW_MODE_BIT       = 0x80000000u >> 2;
[8003]92    uint32 flags( SAVE_VERTEX_NORMALS_BIT );
93
94    IdHelper id(*this, headerName);
95    id.dos_ = &_dos;
96
97    _dos.writeInt16( (int16) HEADER_OP );
98    _dos.writeInt16( length );
99    _dos.writeID( id );
100    _dos.writeInt32( version );
101    _dos.writeInt32( 0 ); // edit revision
102    // TBD need platform-independent method to generate date/time string
103    _dos.writeString( std::string(" "), 32 ); // date and time string for last rev
104    _dos.writeInt16( 0 ); // next group id
105    _dos.writeInt16( 0 ); // next LOD id
106    _dos.writeInt16( 0 ); // next object id
107    _dos.writeInt16( 0 ); // next face id
108    _dos.writeInt16( 1 ); // unit multiplier
109    _dos.writeInt8( units ); // coordinate units
110    _dos.writeInt8( 0 ); // if TRUE, texwhite on new faces
111    _dos.writeUInt32( flags ); // flags
112    _dos.writeFill( sizeof( int32 ) * 6 ); // reserved
113    _dos.writeInt32( 0 ); // projection
114    _dos.writeFill( sizeof( int32 ) * 7 ); // reserved
115    _dos.writeInt16( 0 ); // next DOF id
116    _dos.writeInt16( 1 ); // vertex storage type, should always be 1
117    _dos.writeInt32( 100 ); // DB origin, 100=OpenFlight
118    _dos.writeFloat64( 0. ); // SW corner X
119    _dos.writeFloat64( 0. ); // SW corner Y
120    _dos.writeFloat64( 0. ); // delta X
121    _dos.writeFloat64( 0. ); // delta Y
122    _dos.writeInt16( 0 ); // next sound id
123    _dos.writeInt16( 0 ); // next path id
124    _dos.writeFill( sizeof( int32 ) * 2 ); // reserved
125    _dos.writeInt16( 0 ); // next clip id
126    _dos.writeInt16( 0 ); // next text id
127    _dos.writeInt16( 0 ); // next BSP id
128    _dos.writeInt16( 0 ); // next switch id
129    _dos.writeInt32( 0 ); // reserved
130    _dos.writeFloat64( 0. ); // SW corner lat
131    _dos.writeFloat64( 0. ); // SW corner lon
132    _dos.writeFloat64( 0. ); // NE corner lat
133    _dos.writeFloat64( 0. ); // NE corner lon
134    _dos.writeFloat64( 0. ); // origin lat
135    _dos.writeFloat64( 0. ); // origin lon
136    _dos.writeFloat64( 0. ); // lambert upper lat
137    _dos.writeFloat64( 0. ); // lambert upper lon
138    _dos.writeInt16( 0 ); // next light source id
139    _dos.writeInt16( 0 ); // next light point id
140    _dos.writeInt16( 0 ); // next road id
141    _dos.writeInt16( 0 ); // next CAT id
142    _dos.writeFill( sizeof( int16 ) * 4 ); // reserved
143    _dos.writeInt32( 0 ); // ellipsoid model, 0=WGS84
144    _dos.writeInt16( 0 ); // next adaptive id
145    _dos.writeInt16( 0 ); // next curve id
146    _dos.writeInt16( 0 ); // utm zone
147    _dos.writeFill( 6 ); // reserved
148    _dos.writeFloat64( 0. ); // delta z
149    _dos.writeFloat64( 0. ); // radius
150    _dos.writeInt16( 0 ); // next mesh id
151    _dos.writeInt16( 0 ); // next light system id
152
153    if (version >= 1580)
154    {
155        _dos.writeInt32( 0 ); // reserved
156        _dos.writeFloat64( 0. ); // earth major axis for user defined ellipsoid
157        _dos.writeFloat64( 0. ); // earth minor axis for user defined ellipsoid
158    }
159}
160
161
162// Group flags
163static const unsigned int FORWARD_ANIM     = 0x80000000u >> 1;
164static const unsigned int SWING_ANIM       = 0x80000000u >> 2;
165static const unsigned int BOUND_BOX_FOLLOW = 0x80000000u >> 3;
166static const unsigned int FREEZE_BOUND_BOX = 0x80000000u >> 4;
167static const unsigned int DEFAULT_PARENT   = 0x80000000u >> 5;
168static const unsigned int BACKWARD_ANIM    = 0x80000000u >> 6;
169
170
171//
172//  Convenience routine for writing Group nodes that aren't animated
173//
174void
175FltExportVisitor::writeGroup( const osg::Group& group )
176{
177    int32 flags = 0, loopCount = 0;
178    float32 loopDuration = 0.0f, lastFrameDuration = 0.0f;
179
180    writeGroup(group, flags, loopCount, loopDuration, lastFrameDuration);
181}
182
183
184
185void
186FltExportVisitor::writeGroup( const osg::Group& group,
187                            int32 flags,
188                            int32 loopCount,
189                            float32 loopDuration,
190                            float32 lastFrameDuration)  // <-- placeholder: ignored
191{
192    int16 length( 44 );
193    IdHelper id(*this, group.getName() );
194
195    _records->writeInt16( (int16) GROUP_OP );
196    _records->writeInt16( length );
197    _records->writeID( id );
198    _records->writeInt16( 0 );        // Relative priority
199    _records->writeInt16( 0 );        // Reserved
200    _records->writeUInt32( flags );
201    _records->writeInt16( 0 );        // Special effect ID1
202    _records->writeInt16( 0 );        // Special effect ID2
203    _records->writeInt16( 0 );        // Significance
204    _records->writeInt8( 0 );         // Layer code
205    _records->writeInt8( 0 );         // Reserved
206    _records->writeInt32( 0 );        // Reserved
207    _records->writeInt32( loopCount );
208    _records->writeFloat32( loopDuration );
209    _records->writeFloat32( lastFrameDuration );
210}
211
212
213//
214//  Since OpenFlight doesn't have 'Sequence' records---just Group records that
215//  may, optionally, be animated---this routine sets the animation-related
216//  parameters for a Group record and simply forwards to writeGroup()
217//
218void
219FltExportVisitor::writeSequence( const osg::Sequence& sequence )
220{
221   
222    int32 flags = 0, loopCount = 0;
223    float32 loopDuration = 0.0f, lastFrameDuration = 0.0f;
224
225    osg::Sequence::LoopMode mode;
226    int firstChildDisplayed, lastChildDisplayed;
227    sequence.getInterval(mode, firstChildDisplayed, lastChildDisplayed);
228   
229    if (firstChildDisplayed == 0)
230    {
231        flags |= FORWARD_ANIM;
232    }
233
234    else
235    {
236        flags &= ~FORWARD_ANIM;
237    }
238
239    if (mode == osg::Sequence::SWING)
240    {
241        flags |= SWING_ANIM;
242    }
243
244    else
245    {
246        flags &= ~SWING_ANIM;
247    }
248
249    // Do we loop infinitely, or only a certain number of times?
250    float speedUp;
251    int numReps;
252    sequence.getDuration(speedUp, numReps);
253
254    if (numReps != -1)
255    {
256        loopCount = numReps;
257    }
258
259    else
260    {
261        loopCount = 0;  // == loop continuously
262    }
263
264    // Sum individual frame durations to get the total loopDuration
265    for (unsigned int i = 0; i < sequence.getNumChildren(); ++i)
266    {
267        loopDuration += sequence.getTime(i);
268    }
269
270    lastFrameDuration = sequence.getLastFrameTime();
271
272    writeGroup(sequence, flags, loopCount, loopDuration, lastFrameDuration);
273}
274
275
276void
277FltExportVisitor::writeObject( const osg::Group& group, osgSim::ObjectRecordData* ord )
278{
279    uint16 length( 28 );
280    IdHelper id(*this, group.getName() );
281
282    if (!ord)
283    {
284        std::string warning( "fltexp: writeObject has invalid ObjectRecordData." );
285        osg::notify( osg::WARN ) << warning << std::endl;
286        _fltOpt->getWriteResult().warn( warning );
287        return;
288    }
289
290    _records->writeInt16( (int16) OBJECT_OP );
291    _records->writeInt16( length );
292    _records->writeID( id );
293    _records->writeInt32( ord->_flags );
294    _records->writeInt16( ord->_relativePriority );
295    _records->writeUInt16( ord->_transparency );
296    _records->writeUInt16( ord->_effectID1 );
297    _records->writeUInt16( ord->_effectID2 );
298    _records->writeUInt16( ord->_significance );
299    _records->writeUInt16( 0 ); // reserved
300}
301
302void
303FltExportVisitor::writeDegreeOfFreedom( const osgSim::DOFTransform* dof )
304{
305    const osg::Matrix& invPut = dof->getInversePutMatrix();
306
307    // Origin of DOF coord sys
308    osg::Vec3d origin( invPut.getTrans() );
309
310    osg::Vec3 xAxis( invPut(0,0), invPut(0,1), invPut(0,2) );
311    osg::Vec3 yAxis( invPut(1,0), invPut(1,1), invPut(1,2) );
312    // Reference point along DOF coord sys's X axis
313    osg::Vec3d pointOnXAxis = origin + xAxis;
314    // Reference point in DOF coord sys's X-Y plane
315    osg::Vec3d pointInXYPlane = origin + yAxis;
316
317    // Translations
318    osg::Vec3d minTranslate( dof->getMinTranslate() );
319    osg::Vec3d maxTranslate( dof->getMaxTranslate() );
320    osg::Vec3d currTranslate( dof->getCurrentTranslate() );
321    osg::Vec3d incrTranslate( dof->getIncrementTranslate() );
322
323    // Rotations
324    osg::Vec3d minHPR( dof->getMinHPR() );
325    osg::Vec3d maxHPR( dof->getMaxHPR() );
326    osg::Vec3d currHPR( dof->getCurrentHPR() );
327    osg::Vec3d incrHPR( dof->getIncrementHPR() );
328
329    // Scaling
330    osg::Vec3d minScale( dof->getMinScale() );
331    osg::Vec3d maxScale( dof->getMaxScale() );
332    osg::Vec3d currScale( dof->getCurrentScale() );
333    osg::Vec3d incrScale( dof->getIncrementScale() );
334
335
336    uint16 length( 384 );
337    IdHelper id(*this, dof->getName() );
338
339    _records->writeInt16( (int16) DOF_OP );
340    _records->writeInt16( length );
341    _records->writeID( id );
342    _records->writeInt32( 0 );  // 'Reserved' (unused)
343    _records->writeVec3d( origin );
344    _records->writeVec3d( pointOnXAxis );
345    _records->writeVec3d( pointInXYPlane );
346
347    // Translations
348    _records->writeFloat64( minTranslate.z() );
349    _records->writeFloat64( maxTranslate.z() );
350    _records->writeFloat64( currTranslate.z() );
351    _records->writeFloat64( incrTranslate.z() );
352
353    _records->writeFloat64( minTranslate.y() );
354    _records->writeFloat64( maxTranslate.y() );
355    _records->writeFloat64( currTranslate.y() );
356    _records->writeFloat64( incrTranslate.y() );
357
358    _records->writeFloat64( minTranslate.x() );
359    _records->writeFloat64( maxTranslate.x() );
360    _records->writeFloat64( currTranslate.x() );
361    _records->writeFloat64( incrTranslate.x() );
362
363    // Rotations: 0 = Yaw, 1 = Pitch, 2 = Roll
364    _records->writeFloat64( osg::RadiansToDegrees(minHPR[1]) );
365    _records->writeFloat64( osg::RadiansToDegrees(maxHPR[1]) );
366    _records->writeFloat64( osg::RadiansToDegrees(currHPR[1]) );
367    _records->writeFloat64( osg::RadiansToDegrees(incrHPR[1]) );
368
369    _records->writeFloat64( osg::RadiansToDegrees(minHPR[2]) );
370    _records->writeFloat64( osg::RadiansToDegrees(maxHPR[2]) );
371    _records->writeFloat64( osg::RadiansToDegrees(currHPR[2]) );
372    _records->writeFloat64( osg::RadiansToDegrees(incrHPR[2]) );
373
374    _records->writeFloat64( osg::RadiansToDegrees(minHPR[0]) );
375    _records->writeFloat64( osg::RadiansToDegrees(maxHPR[0]) );
376    _records->writeFloat64( osg::RadiansToDegrees(currHPR[0]) );
377    _records->writeFloat64( osg::RadiansToDegrees(incrHPR[0]) );
378
379    // Scaling
380    _records->writeFloat64( minScale.z() );
381    _records->writeFloat64( maxScale.z() );
382    _records->writeFloat64( currScale.z() );
383    _records->writeFloat64( incrScale.z() );
384
385    _records->writeFloat64( minScale.y() );
386    _records->writeFloat64( maxScale.y() );
387    _records->writeFloat64( currScale.y() );
388    _records->writeFloat64( incrScale.y() );
389
390    _records->writeFloat64( minScale.x() );
391    _records->writeFloat64( maxScale.x() );
392    _records->writeFloat64( currScale.x() );
393    _records->writeFloat64( incrScale.y() );
394
395    _records->writeInt32( dof->getLimitationFlags() );  //  Constraint flags
396    _records->writeInt32( 0 );                          // 'Reserved' (unused)
397
398}
399
400// Parent pool override flags
401static const unsigned long COLOR_PALETTE_OVERRIDE        = 0x80000000u >> 0;
402static const unsigned long MATERIAL_PALETTE_OVERRIDE     = 0x80000000u >> 1;
403static const unsigned long TEXTURE_PALETTE_OVERRIDE      = 0x80000000u >> 2;
404static const unsigned long LINE_STYLE_PALETTE_OVERRIDE   = 0x80000000u >> 3;
405static const unsigned long SOUND_PALETTE_OVERRIDE        = 0x80000000u >> 4;
406static const unsigned long LIGHT_SOURCE_PALETTE_OVERRIDE = 0x80000000u >> 5;
407static const unsigned long LIGHT_POINT_PALETTE_OVERRIDE  = 0x80000000u >> 6;
408static const unsigned long SHADER_PALETTE_OVERRIDE       = 0x80000000u >> 7;
409
410void
411FltExportVisitor::writeExternalReference( const osg::ProxyNode& proxy )
412{
413    uint16 length( 216 );
414
415    // Set sane defaults for the override flags
416    unsigned long flags = COLOR_PALETTE_OVERRIDE       |
417                          MATERIAL_PALETTE_OVERRIDE    |
418                          TEXTURE_PALETTE_OVERRIDE     |
419                          LIGHT_POINT_PALETTE_OVERRIDE |
420                          SHADER_PALETTE_OVERRIDE ;
421
422    // Selectively turn off overrides for resources we don't need
[9063]423    const ParentPools* pp = dynamic_cast<const ParentPools*>(proxy.getUserData() );
424   
[8003]425    if (pp && pp->getColorPool() )
426      flags &= ~COLOR_PALETTE_OVERRIDE;
427
428    if (pp && pp->getMaterialPool() )
429      flags &= ~MATERIAL_PALETTE_OVERRIDE;
430
431    if (pp && pp->getTexturePool() )
432      flags &= ~TEXTURE_PALETTE_OVERRIDE;
433
434    if (pp && pp->getLightSourcePool() )
435      flags &= ~LIGHT_SOURCE_PALETTE_OVERRIDE;
436
437    if (pp && pp->getLPAppearancePool() )
438      flags &= ~LIGHT_POINT_PALETTE_OVERRIDE;
439
440    if (pp && pp->getShaderPool() )
441      flags &= ~SHADER_PALETTE_OVERRIDE;
442
443    _records->writeInt16( (int16) EXTERNAL_REFERENCE_OP );
444    _records->writeInt16( length );
445    _records->writeString(proxy.getFileName(0), 200);
446    _records->writeInt32(0);   // Reserved
447    _records->writeInt32(flags);
448    _records->writeInt16(0);   // ViewAsBoundingBox flag
449    _records->writeInt16(0);   // Reserved
450}
451
452void
453FltExportVisitor::writeLevelOfDetail( const osg::LOD& lod,
454                                    osg::Vec3d const& center,
455                                    double switchInDist,
456                                    double switchOutDist)
457{
458    uint16 length( 80 );
459    IdHelper id(*this, lod.getName() );
460
461    _records->writeInt16( (int16) LOD_OP );
462    _records->writeInt16( length );
463    _records->writeID( id );
464    _records->writeInt32( 0 );                 // 'Reserved' field
465    _records->writeFloat64( switchInDist );
466    _records->writeFloat64( switchOutDist );   // Switch-out distance
467    _records->writeInt16( 0 );                 // Special Effect ID1
468    _records->writeInt16( 0 );                 // Special Effect ID2
469    _records->writeInt32( 0 );                 // Flags
470    _records->writeFloat64( center.x() );
471    _records->writeFloat64( center.y() );
472    _records->writeFloat64( center.z() );
473    _records->writeFloat64( 0 );               // Transition range
474    _records->writeFloat64( 0 );               // Significant size
475
476}
477
478void
479FltExportVisitor::writeLightSource( const osg::LightSource& node )
480{
481
482    static const unsigned int ENABLED = 0x80000000u >> 0;
483    static const unsigned int GLOBAL  = 0x80000000u >> 1;
484
485    osg::Light const* light = node.getLight();
486    int index = _lightSourcePalette->add(light);
487
488    osg::Vec4d const& lightPos = light->getPosition();
489    osg::Vec3f const& lightDir = light->getDirection();
490
491    uint32 flags = 0;
492    osg::StateSet const* ss = getCurrentStateSet();
493    if (ss->getMode(GL_LIGHT0 + light->getLightNum() ) & osg::StateAttribute::ON)
494    {
495        flags |= ENABLED;
496    }
497
498    // If this light is enabled for the node at the top of our StateSet stack,
499    // assume it is 'global' for OpenFlight's purposes
500    ss = _stateSetStack.front().get();
501    if (ss->getMode(GL_LIGHT0 + light->getLightNum() ) & osg::StateAttribute::ON)
502    {
503        flags |= GLOBAL;
504    }
505
506    uint16 length( 64 );
507    IdHelper id(*this, node.getName() );
508
509    _records->writeInt16( (int16) LIGHT_SOURCE_OP );
510    _records->writeInt16( length );
511    _records->writeID( id );
512    _records->writeInt32( 0 );              // Reserved
513    _records->writeInt32( index );          // Index into light source palette
514    _records->writeInt32( 0 );              // Reserved
515    _records->writeUInt32( flags );         // Flags
516    _records->writeInt32( 0 );              // Reserved
517    _records->writeVec3d( osg::Vec3d(
518                              lightPos.x() , lightPos.y() , lightPos.z() ) );
519
520    // TODO: Verify that indices 0 and 1 correspond to yaw and pitch
521    _records->writeFloat32( lightDir[0] );  // Yaw
522    _records->writeFloat32( lightDir[1] );  // Pitch
523}
524
525
526
527void
528FltExportVisitor::writeSwitch( const osgSim::MultiSwitch* ms )
529{
530    int32 currMask = ms->getActiveSwitchSet();
531    int32 numMasks = ms->getSwitchSetList().size();
532    int32 numWordsPerMask = ms->getNumChildren() / 32;
533    if (ms->getNumChildren() % 32 != 0) ++numWordsPerMask;
534   
535    uint16 length( 28 + numMasks * numWordsPerMask * sizeof(int32) );
536    IdHelper id(*this, ms->getName() );
537
538    _records->writeInt16( (int16) SWITCH_OP );
539    _records->writeInt16( length );
540    _records->writeID( id );
541    _records->writeInt32( 0 );  // <-- 'Reserved' (unused)
542    _records->writeInt32( currMask );
543    _records->writeInt32( numMasks );
544    _records->writeInt32( numWordsPerMask );
545
546    // For each mask...
547    for (int i = 0; i < numMasks; ++i)
548    {
549        // ... write out the set of 32-bit words comprising the mask
550        uint32 maskWord = 0;
551        const osgSim::MultiSwitch::ValueList& maskBits = ms->getValueList(i);
552
553        for (size_t j = 0; j < maskBits.size(); ++j)
554        {
555            // If this bit is set, set the corresponding mask word
556            if (maskBits[j]) maskWord |= 1 << (j % 32);
557
558            // If we just set the 31st (last) bit of the current word, need
559            // to write it out and reset prior to continuing the loop
560            if ( (j + 1) % 32 == 0 )
561            {
562                _records->writeUInt32(maskWord);
563                maskWord = 0;
564            }
565        }
566
567        // If the mask size wasn't a multiple of 32, need to write out
568        // the final word containing the 'remainder' bits
569        if (maskBits.size() % 32 != 0)
570        {
571            _records->writeUInt32(maskWord);
572        }
573    }
574
575}
576
577
578void
579FltExportVisitor::writeSwitch( const osg::Switch* sw )
580{
581    // An osg::Switch is just a special case of an osgSim::MultiSwitch
582    // that only has a single mask
583    int32 currMask = 0;
584    int32 numMasks = 1;
585    int32 numWordsPerMask = sw->getNumChildren() / 32;
586    if (sw->getNumChildren() % 32 != 0) ++numWordsPerMask;
587
588    uint16 length( 28 + numMasks * numWordsPerMask * sizeof(int32) );
589    IdHelper id(*this, sw->getName() );
590
591    _records->writeInt16( (int16) SWITCH_OP );
592    _records->writeInt16( length );
593    _records->writeID( id );
594    _records->writeInt32( 0 );  // <-- 'Reserved' (unused)
595    _records->writeInt32( currMask );
596    _records->writeInt32( numMasks );
597    _records->writeInt32( numWordsPerMask );
598
599    // Bust the mask up into as many 32-bit words as are necessary to hold it
600    uint32 maskWord = 0;
601    const osg::Switch::ValueList& maskBits = sw->getValueList();
602
603    for (size_t i = 0; i < maskBits.size(); ++i)
604    {
605        // If this bit is set, set the corresponding mask word
606        if (maskBits[i]) maskWord |= 1 << (i % 32);
607
608        // If we just set the 31st (last) bit of the current word, need
609        // to write it out and reset prior to continuing the loop
610        if ( (i + 1) % 32 == 0 )
611        {
612            _records->writeUInt32(maskWord);
613            maskWord = 0;
614        }
615    }
616
617    // If the mask size wasn't a multiple of 32, need to write out
618    // the final word containing the 'remainder' bits
619    if (maskBits.size() % 32 != 0)
620    {
621        _records->writeUInt32(maskWord);
622    }
623
624}
625
626void
627FltExportVisitor::writeLightPoint( const osgSim::LightPointNode* lpn )
628{
629    enum Directionality
630    {
631        OMNIDIRECTIONAL = 0,
632        UNIDIRECTIONAL = 1,
633        BIDIRECTIONAL = 2
634    };
635    enum DisplayMode
636    {
637        RASTER = 0,
638        CALLIG = 1,
639        EITHER = 2
640    };
641    enum Modes
642    {
643        ENABLE = 0,
644        DISABLE = 1
645    };
646    enum Flags
647    {
648        NO_BACK_COLOR    = 0x80000000u >> 1,
649        CALLIGRAPHIC    = 0x80000000u >> 3,
650        REFLECTIVE        = 0x80000000u >> 4,
651        PERSPECTIVE        = 0x80000000u >> 8,
652        FLASHING        = 0x80000000u >> 9,
653        ROTATING        = 0x80000000u >> 10,
654        ROTATE_CC        = 0x80000000u >> 11,
655        VISIBLE_DAY        = 0x80000000u >> 15,
656        VISIBLE_DUSK    = 0x80000000u >> 16,
657        VISIBLE_NIGHT    = 0x80000000u >> 17
658    };
659    int32 flags( NO_BACK_COLOR );
660
661    if (lpn->getNumLightPoints() == 0)
662        return;
663
664    // In OSG, each LightPoint within a LightPointNode  can have different appearance
[8563]665    // parameters, but in OpenFlight, a Light Point Record contains a list of homogeneous
[8003]666    // vertices. To be correct, we'd have to look at all LightPoints in the LightPointNode
667    // and spew out multiple FLT records for each group that shared common appearance
668    // parameters. Instead, we cheat: We take the first LightPoint and use its appearance
669    // parameters for all LightPoints in the LightPointNode.
670    const osgSim::LightPoint& lp0 = lpn->getLightPoint( 0 );
671
672    // No really good mapping between OSG and FLT light point animations.
673    float32 animPeriod( 0.f );
674    float32 animEnabled( 0.f );
675    float32 animPhaseDelay( 0.f );
676    if (lp0._blinkSequence != NULL)
677    {
678        flags |= FLASHING;
679        animPeriod = 4.f;
680        animEnabled = 2.f;
681        animPhaseDelay = lp0._blinkSequence->getPhaseShift();
682    }
683
[8563]684    // Note that true bidirectional light points are currently unsupported (they are unavailable
[8003]685    // in OSG, so we never write them out to FLT as BIDIRECTIONAL.
686    int32 directionality( OMNIDIRECTIONAL );
687    float32 horizLobe( 360.f );
688    float32 vertLobe( 360.f );
689    float32 lobeRoll( 0.f );
690    const osgSim::DirectionalSector* ds = dynamic_cast< osgSim::DirectionalSector* >( lp0._sector.get() );
691    if (ds)
692    {
693        directionality = UNIDIRECTIONAL;
694        horizLobe = osg::RadiansToDegrees( ds->getHorizLobeAngle() );
695        vertLobe = osg::RadiansToDegrees( ds->getVertLobeAngle() );
696        lobeRoll = osg::RadiansToDegrees( ds->getLobeRollAngle() );
697    }
698
699    {
700        // Braces req'd to invoke idHelper destructor (and potentially
701        // write LongID record) before Push Record.
702
703        const uint16 length( 156 );
704        IdHelper id( *this, lpn->getName() );
705
706        _records->writeInt16( (int16) LIGHT_POINT_OP );
707        _records->writeInt16( length );
708        _records->writeID( id );
709        _records->writeInt16( 0 ); // Surface material code
710        _records->writeInt16( 0 ); // Feature ID
[9581]711        _records->writeUInt32( ~0u ); // OpenFlight erronously say -1, so will assume ~0u is OK.  Back color for bidirectional
[8003]712        _records->writeInt32( EITHER ); // Display mode
713        _records->writeFloat32( lp0._intensity ); // Intensity
714        _records->writeFloat32( 0.f ); // Back intensity TBD
715        _records->writeFloat32( 0.f ); // min defocus
716        _records->writeFloat32( 0.f ); // max defocus
717        _records->writeInt32( DISABLE ); // Fading mode
718        _records->writeInt32( DISABLE ); // Fog punch mode
719        _records->writeInt32( DISABLE ); // Directional mode
720        _records->writeInt32( 0 ); // Range mode
721        _records->writeFloat32( lpn->getMinPixelSize() ); // min pixel size
722        _records->writeFloat32( lpn->getMaxPixelSize() ); // max pixel size
723        _records->writeFloat32( lp0._radius * 2.f ); // Actual size
724        _records->writeFloat32( 1.f ); // transparent falloff pixel size
725        _records->writeFloat32( 1.f ); // Transparent falloff exponent
726        _records->writeFloat32( 1.f ); // Transparent falloff scalar
727        _records->writeFloat32( 0.f ); // Transparent falloff clamp
728        _records->writeFloat32( 1.f ); // Fog scalar
729        _records->writeFloat32( 0.f ); // Reserved
730        _records->writeFloat32( 0.f ); // Size difference threshold
731        _records->writeInt32( directionality ); // Directionality
732        _records->writeFloat32( horizLobe ); // Horizontal lobe angle
733        _records->writeFloat32( vertLobe ); // Vertical lobe angle
734        _records->writeFloat32( lobeRoll ); // Lobe roll angle
735        _records->writeFloat32( 0.f ); // Directional falloff exponent
736        _records->writeFloat32( 0.f ); // Directional ambient intensity
737        _records->writeFloat32( animPeriod ); // Animation period in seconds
[8563]738        _records->writeFloat32( animPhaseDelay ); // Animation phase delay in seconds
[8003]739        _records->writeFloat32( animEnabled ); // Animation enabled period in seconds
740        _records->writeFloat32( 1.f ); // Significance
741        _records->writeInt32( 0 ); // Calligraphic draw order
742        _records->writeInt32( flags ); // Flags
743        _records->writeVec3f( osg::Vec3f( 0.f, 0.f, 0.f ) ); // Axis of rotation
744    }
745
746    {
[8086]747        osg::ref_ptr< osg::Vec3dArray > v = new osg::Vec3dArray( lpn->getNumLightPoints() );
[8003]748        osg::ref_ptr< osg::Vec4Array > c = new osg::Vec4Array( lpn->getNumLightPoints() );
749        osg::ref_ptr< osg::Vec3Array > n = new osg::Vec3Array( lpn->getNumLightPoints() );
750        osg::Vec3f normal( 0.f, 0.f, 1.f );
751
752        unsigned int idx;
753        for( idx=0; idx<lpn->getNumLightPoints(); idx++)
754        {
755            const osgSim::LightPoint& lp = lpn->getLightPoint( idx );
756            (*v)[ idx ] = lp._position;
757            (*c)[ idx ] = lp._color;
758
759            const osgSim::DirectionalSector* ds = dynamic_cast< osgSim::DirectionalSector* >( lp._sector.get() );
760            if (ds)
761                normal = ds->getDirection();
762            (*n)[ idx ] = normal;
763        }
[8086]764        _vertexPalette->add( (const osg::Array*)NULL, v.get(), c.get(), n.get(), NULL, true, true, false );
[8003]765    }
766
767    writeMatrix( lpn->getUserData() );
768    writeComment( *lpn );
769    writePush();
770    writeVertexList( 0, lpn->getNumLightPoints() );
771    writePop();
772}
773
774
775void
776FltExportVisitor::writeColorPalette()
777{
778    // FLT exporter doesn't use a color palette but writes
779    // a bogus one to satisfy loaders that require it.
780    uint16 length( 4228 );
781
782    _dos.writeInt16( (int16) COLOR_PALETTE_OP );
783    _dos.writeInt16( length );
784    _dos.writeFill( 128 ); // Reserved
785    int idx;
786    for( idx=0; idx<1024; idx++)
787        _dos.writeUInt32( 0xffffffff ); // Color n
788}
789
790
791
792
793}
Note: See TracBrowser for help on using the browser.