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

Revision 10764, 27.2 kB (checked in by robert, 5 years ago)

<iterator>, <stdlib.h> and <ctype.h> includes required for QNX compiler

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