/* * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or (at * your option) any later version. The full license is in the LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ // // Copyright(c) 2008 Skew Matrix Software LLC. // #include "FltExportVisitor.h" #include "ExportOptions.h" #include "VertexPaletteManager.h" #include "LightSourcePaletteManager.h" #include "DataOutputStream.h" #include "Opcodes.h" #include #include #include #include #include #include #include #include #include #include #include // FIXME: This header was copied verbatim from the importer, with the only change // being that the symbols it defines are placed in namespace 'fltexp' instead // of 'flt'. Thus, this one-off copy has to be kept in sync with the // importer until the reader/writer are unified... #include "Pools.h" namespace flt { void FltExportVisitor::writeHeader( const std::string& headerName ) { int16 length; int32 version; const int ver = _fltOpt->getFlightFileVersionNumber(); if (ver == ExportOptions::VERSION_15_7) { length = 304; version = 1570; } else if (ver == ExportOptions::VERSION_15_8) { length = 324; version = 1580; } else // ExportOptions::VERSION_16_1: { length = 324; version = 1610; } int8 units; switch( _fltOpt->getFlightUnits() ) { case ExportOptions::KILOMETERS: units = 1; break; case ExportOptions::FEET: units = 4; break; case ExportOptions::INCHES: units = 5; break; case ExportOptions::NAUTICAL_MILES: units = 8; break; default: case ExportOptions::METERS: units = 0; break; } static const unsigned int SAVE_VERTEX_NORMALS_BIT = 0x80000000u >> 0; //static const unsigned int PACKED_COLOR_MODE_BIT = 0x80000000u >> 1; //static const unsigned int CAD_VIEW_MODE_BIT = 0x80000000u >> 2; uint32 flags( SAVE_VERTEX_NORMALS_BIT ); IdHelper id(*this, headerName); id.dos_ = &_dos; _dos.writeInt16( (int16) HEADER_OP ); _dos.writeInt16( length ); _dos.writeID( id ); _dos.writeInt32( version ); _dos.writeInt32( 0 ); // edit revision // TBD need platform-independent method to generate date/time string _dos.writeString( std::string(" "), 32 ); // date and time string for last rev _dos.writeInt16( 0 ); // next group id _dos.writeInt16( 0 ); // next LOD id _dos.writeInt16( 0 ); // next object id _dos.writeInt16( 0 ); // next face id _dos.writeInt16( 1 ); // unit multiplier _dos.writeInt8( units ); // coordinate units _dos.writeInt8( 0 ); // if TRUE, texwhite on new faces _dos.writeUInt32( flags ); // flags _dos.writeFill( sizeof( int32 ) * 6 ); // reserved _dos.writeInt32( 0 ); // projection _dos.writeFill( sizeof( int32 ) * 7 ); // reserved _dos.writeInt16( 0 ); // next DOF id _dos.writeInt16( 1 ); // vertex storage type, should always be 1 _dos.writeInt32( 100 ); // DB origin, 100=OpenFlight _dos.writeFloat64( 0. ); // SW corner X _dos.writeFloat64( 0. ); // SW corner Y _dos.writeFloat64( 0. ); // delta X _dos.writeFloat64( 0. ); // delta Y _dos.writeInt16( 0 ); // next sound id _dos.writeInt16( 0 ); // next path id _dos.writeFill( sizeof( int32 ) * 2 ); // reserved _dos.writeInt16( 0 ); // next clip id _dos.writeInt16( 0 ); // next text id _dos.writeInt16( 0 ); // next BSP id _dos.writeInt16( 0 ); // next switch id _dos.writeInt32( 0 ); // reserved _dos.writeFloat64( 0. ); // SW corner lat _dos.writeFloat64( 0. ); // SW corner lon _dos.writeFloat64( 0. ); // NE corner lat _dos.writeFloat64( 0. ); // NE corner lon _dos.writeFloat64( 0. ); // origin lat _dos.writeFloat64( 0. ); // origin lon _dos.writeFloat64( 0. ); // lambert upper lat _dos.writeFloat64( 0. ); // lambert upper lon _dos.writeInt16( 0 ); // next light source id _dos.writeInt16( 0 ); // next light point id _dos.writeInt16( 0 ); // next road id _dos.writeInt16( 0 ); // next CAT id _dos.writeFill( sizeof( int16 ) * 4 ); // reserved _dos.writeInt32( 0 ); // ellipsoid model, 0=WGS84 _dos.writeInt16( 0 ); // next adaptive id _dos.writeInt16( 0 ); // next curve id _dos.writeInt16( 0 ); // utm zone _dos.writeFill( 6 ); // reserved _dos.writeFloat64( 0. ); // delta z _dos.writeFloat64( 0. ); // radius _dos.writeInt16( 0 ); // next mesh id _dos.writeInt16( 0 ); // next light system id if (version >= 1580) { _dos.writeInt32( 0 ); // reserved _dos.writeFloat64( 0. ); // earth major axis for user defined ellipsoid _dos.writeFloat64( 0. ); // earth minor axis for user defined ellipsoid } } // Group flags static const unsigned int FORWARD_ANIM = 0x80000000u >> 1; static const unsigned int SWING_ANIM = 0x80000000u >> 2; static const unsigned int BOUND_BOX_FOLLOW = 0x80000000u >> 3; static const unsigned int FREEZE_BOUND_BOX = 0x80000000u >> 4; static const unsigned int DEFAULT_PARENT = 0x80000000u >> 5; static const unsigned int BACKWARD_ANIM = 0x80000000u >> 6; // // Convenience routine for writing Group nodes that aren't animated // void FltExportVisitor::writeGroup( const osg::Group& group ) { int32 flags = 0, loopCount = 0; float32 loopDuration = 0.0f, lastFrameDuration = 0.0f; writeGroup(group, flags, loopCount, loopDuration, lastFrameDuration); } void FltExportVisitor::writeGroup( const osg::Group& group, int32 flags, int32 loopCount, float32 loopDuration, float32 lastFrameDuration) // <-- placeholder: ignored { int16 length( 44 ); IdHelper id(*this, group.getName() ); _records->writeInt16( (int16) GROUP_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt16( 0 ); // Relative priority _records->writeInt16( 0 ); // Reserved _records->writeUInt32( flags ); _records->writeInt16( 0 ); // Special effect ID1 _records->writeInt16( 0 ); // Special effect ID2 _records->writeInt16( 0 ); // Significance _records->writeInt8( 0 ); // Layer code _records->writeInt8( 0 ); // Reserved _records->writeInt32( 0 ); // Reserved _records->writeInt32( loopCount ); _records->writeFloat32( loopDuration ); _records->writeFloat32( lastFrameDuration ); } // // Since OpenFlight doesn't have 'Sequence' records---just Group records that // may, optionally, be animated---this routine sets the animation-related // parameters for a Group record and simply forwards to writeGroup() // void FltExportVisitor::writeSequence( const osg::Sequence& sequence ) { int32 flags = 0, loopCount = 0; float32 loopDuration = 0.0f, lastFrameDuration = 0.0f; osg::Sequence::LoopMode mode; int firstChildDisplayed, lastChildDisplayed; sequence.getInterval(mode, firstChildDisplayed, lastChildDisplayed); if (firstChildDisplayed == 0) { flags |= FORWARD_ANIM; } else { flags &= ~FORWARD_ANIM; } if (mode == osg::Sequence::SWING) { flags |= SWING_ANIM; } else { flags &= ~SWING_ANIM; } // Do we loop infinitely, or only a certain number of times? float speedUp; int numReps; sequence.getDuration(speedUp, numReps); if (numReps != -1) { loopCount = numReps; } else { loopCount = 0; // == loop continuously } // Sum individual frame durations to get the total loopDuration for (unsigned int i = 0; i < sequence.getNumChildren(); ++i) { loopDuration += sequence.getTime(i); } lastFrameDuration = sequence.getLastFrameTime(); writeGroup(sequence, flags, loopCount, loopDuration, lastFrameDuration); } void FltExportVisitor::writeObject( const osg::Group& group, osgSim::ObjectRecordData* ord ) { uint16 length( 28 ); IdHelper id(*this, group.getName() ); if (!ord) { std::string warning( "fltexp: writeObject has invalid ObjectRecordData." ); OSG_WARN << warning << std::endl; _fltOpt->getWriteResult().warn( warning ); return; } _records->writeInt16( (int16) OBJECT_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt32( ord->_flags ); _records->writeInt16( ord->_relativePriority ); _records->writeUInt16( ord->_transparency ); _records->writeUInt16( ord->_effectID1 ); _records->writeUInt16( ord->_effectID2 ); _records->writeUInt16( ord->_significance ); _records->writeUInt16( 0 ); // reserved } void FltExportVisitor::writeDegreeOfFreedom( const osgSim::DOFTransform* dof ) { const osg::Matrix& invPut = dof->getInversePutMatrix(); // Origin of DOF coord sys osg::Vec3d origin( invPut.getTrans() ); osg::Vec3 xAxis( invPut(0,0), invPut(0,1), invPut(0,2) ); osg::Vec3 yAxis( invPut(1,0), invPut(1,1), invPut(1,2) ); // Reference point along DOF coord sys's X axis osg::Vec3d pointOnXAxis = origin + xAxis; // Reference point in DOF coord sys's X-Y plane osg::Vec3d pointInXYPlane = origin + yAxis; // Translations osg::Vec3d minTranslate( dof->getMinTranslate() ); osg::Vec3d maxTranslate( dof->getMaxTranslate() ); osg::Vec3d currTranslate( dof->getCurrentTranslate() ); osg::Vec3d incrTranslate( dof->getIncrementTranslate() ); // Rotations osg::Vec3d minHPR( dof->getMinHPR() ); osg::Vec3d maxHPR( dof->getMaxHPR() ); osg::Vec3d currHPR( dof->getCurrentHPR() ); osg::Vec3d incrHPR( dof->getIncrementHPR() ); // Scaling osg::Vec3d minScale( dof->getMinScale() ); osg::Vec3d maxScale( dof->getMaxScale() ); osg::Vec3d currScale( dof->getCurrentScale() ); osg::Vec3d incrScale( dof->getIncrementScale() ); uint16 length( 384 ); IdHelper id(*this, dof->getName() ); _records->writeInt16( (int16) DOF_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt32( 0 ); // 'Reserved' (unused) _records->writeVec3d( origin ); _records->writeVec3d( pointOnXAxis ); _records->writeVec3d( pointInXYPlane ); // Translations _records->writeFloat64( minTranslate.z() ); _records->writeFloat64( maxTranslate.z() ); _records->writeFloat64( currTranslate.z() ); _records->writeFloat64( incrTranslate.z() ); _records->writeFloat64( minTranslate.y() ); _records->writeFloat64( maxTranslate.y() ); _records->writeFloat64( currTranslate.y() ); _records->writeFloat64( incrTranslate.y() ); _records->writeFloat64( minTranslate.x() ); _records->writeFloat64( maxTranslate.x() ); _records->writeFloat64( currTranslate.x() ); _records->writeFloat64( incrTranslate.x() ); // Rotations: 0 = Yaw, 1 = Pitch, 2 = Roll _records->writeFloat64( osg::RadiansToDegrees(minHPR[1]) ); _records->writeFloat64( osg::RadiansToDegrees(maxHPR[1]) ); _records->writeFloat64( osg::RadiansToDegrees(currHPR[1]) ); _records->writeFloat64( osg::RadiansToDegrees(incrHPR[1]) ); _records->writeFloat64( osg::RadiansToDegrees(minHPR[2]) ); _records->writeFloat64( osg::RadiansToDegrees(maxHPR[2]) ); _records->writeFloat64( osg::RadiansToDegrees(currHPR[2]) ); _records->writeFloat64( osg::RadiansToDegrees(incrHPR[2]) ); _records->writeFloat64( osg::RadiansToDegrees(minHPR[0]) ); _records->writeFloat64( osg::RadiansToDegrees(maxHPR[0]) ); _records->writeFloat64( osg::RadiansToDegrees(currHPR[0]) ); _records->writeFloat64( osg::RadiansToDegrees(incrHPR[0]) ); // Scaling _records->writeFloat64( minScale.z() ); _records->writeFloat64( maxScale.z() ); _records->writeFloat64( currScale.z() ); _records->writeFloat64( incrScale.z() ); _records->writeFloat64( minScale.y() ); _records->writeFloat64( maxScale.y() ); _records->writeFloat64( currScale.y() ); _records->writeFloat64( incrScale.y() ); _records->writeFloat64( minScale.x() ); _records->writeFloat64( maxScale.x() ); _records->writeFloat64( currScale.x() ); _records->writeFloat64( incrScale.y() ); _records->writeInt32( dof->getLimitationFlags() ); // Constraint flags _records->writeInt32( 0 ); // 'Reserved' (unused) } // Parent pool override flags static const unsigned long COLOR_PALETTE_OVERRIDE = 0x80000000u >> 0; static const unsigned long MATERIAL_PALETTE_OVERRIDE = 0x80000000u >> 1; static const unsigned long TEXTURE_PALETTE_OVERRIDE = 0x80000000u >> 2; static const unsigned long LINE_STYLE_PALETTE_OVERRIDE = 0x80000000u >> 3; static const unsigned long SOUND_PALETTE_OVERRIDE = 0x80000000u >> 4; static const unsigned long LIGHT_SOURCE_PALETTE_OVERRIDE = 0x80000000u >> 5; static const unsigned long LIGHT_POINT_PALETTE_OVERRIDE = 0x80000000u >> 6; static const unsigned long SHADER_PALETTE_OVERRIDE = 0x80000000u >> 7; void FltExportVisitor::writeExternalReference( const osg::ProxyNode& proxy ) { uint16 length( 216 ); // Set sane defaults for the override flags unsigned long flags = COLOR_PALETTE_OVERRIDE | MATERIAL_PALETTE_OVERRIDE | TEXTURE_PALETTE_OVERRIDE | LIGHT_POINT_PALETTE_OVERRIDE | SHADER_PALETTE_OVERRIDE ; // Selectively turn off overrides for resources we don't need const ParentPools* pp = dynamic_cast(proxy.getUserData() ); if (pp && pp->getColorPool() ) flags &= ~COLOR_PALETTE_OVERRIDE; if (pp && pp->getMaterialPool() ) flags &= ~MATERIAL_PALETTE_OVERRIDE; if (pp && pp->getTexturePool() ) flags &= ~TEXTURE_PALETTE_OVERRIDE; if (pp && pp->getLightSourcePool() ) flags &= ~LIGHT_SOURCE_PALETTE_OVERRIDE; if (pp && pp->getLPAppearancePool() ) flags &= ~LIGHT_POINT_PALETTE_OVERRIDE; if (pp && pp->getShaderPool() ) flags &= ~SHADER_PALETTE_OVERRIDE; _records->writeInt16( (int16) EXTERNAL_REFERENCE_OP ); _records->writeInt16( length ); _records->writeString(proxy.getFileName(0), 200); _records->writeInt32(0); // Reserved _records->writeInt32(flags); _records->writeInt16(0); // ViewAsBoundingBox flag _records->writeInt16(0); // Reserved } void FltExportVisitor::writeLevelOfDetail( const osg::LOD& lod, osg::Vec3d const& center, double switchInDist, double switchOutDist) { uint16 length( 80 ); IdHelper id(*this, lod.getName() ); _records->writeInt16( (int16) LOD_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt32( 0 ); // 'Reserved' field _records->writeFloat64( switchInDist ); _records->writeFloat64( switchOutDist ); // Switch-out distance _records->writeInt16( 0 ); // Special Effect ID1 _records->writeInt16( 0 ); // Special Effect ID2 _records->writeInt32( 0 ); // Flags _records->writeFloat64( center.x() ); _records->writeFloat64( center.y() ); _records->writeFloat64( center.z() ); _records->writeFloat64( 0 ); // Transition range _records->writeFloat64( 0 ); // Significant size } void FltExportVisitor::writeLightSource( const osg::LightSource& node ) { static const unsigned int ENABLED = 0x80000000u >> 0; static const unsigned int GLOBAL = 0x80000000u >> 1; osg::Light const* light = node.getLight(); int index = _lightSourcePalette->add(light); osg::Vec4d const& lightPos = light->getPosition(); osg::Vec3f const& lightDir = light->getDirection(); uint32 flags = 0; osg::StateSet const* ss = getCurrentStateSet(); if (ss->getMode(GL_LIGHT0 + light->getLightNum() ) & osg::StateAttribute::ON) { flags |= ENABLED; } // If this light is enabled for the node at the top of our StateSet stack, // assume it is 'global' for OpenFlight's purposes ss = _stateSetStack.front().get(); if (ss->getMode(GL_LIGHT0 + light->getLightNum() ) & osg::StateAttribute::ON) { flags |= GLOBAL; } uint16 length( 64 ); IdHelper id(*this, node.getName() ); _records->writeInt16( (int16) LIGHT_SOURCE_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt32( 0 ); // Reserved _records->writeInt32( index ); // Index into light source palette _records->writeInt32( 0 ); // Reserved _records->writeUInt32( flags ); // Flags _records->writeInt32( 0 ); // Reserved _records->writeVec3d( osg::Vec3d( lightPos.x() , lightPos.y() , lightPos.z() ) ); // TODO: Verify that indices 0 and 1 correspond to yaw and pitch _records->writeFloat32( lightDir[0] ); // Yaw _records->writeFloat32( lightDir[1] ); // Pitch } void FltExportVisitor::writeSwitch( const osgSim::MultiSwitch* ms ) { int32 currMask = ms->getActiveSwitchSet(); int32 numMasks = ms->getSwitchSetList().size(); int32 numWordsPerMask = ms->getNumChildren() / 32; if (ms->getNumChildren() % 32 != 0) ++numWordsPerMask; uint16 length( 28 + numMasks * numWordsPerMask * sizeof(int32) ); IdHelper id(*this, ms->getName() ); _records->writeInt16( (int16) SWITCH_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt32( 0 ); // <-- 'Reserved' (unused) _records->writeInt32( currMask ); _records->writeInt32( numMasks ); _records->writeInt32( numWordsPerMask ); // For each mask... for (int i = 0; i < numMasks; ++i) { // ... write out the set of 32-bit words comprising the mask uint32 maskWord = 0; const osgSim::MultiSwitch::ValueList& maskBits = ms->getValueList(i); for (size_t j = 0; j < maskBits.size(); ++j) { // If this bit is set, set the corresponding mask word if (maskBits[j]) maskWord |= 1 << (j % 32); // If we just set the 31st (last) bit of the current word, need // to write it out and reset prior to continuing the loop if ( (j + 1) % 32 == 0 ) { _records->writeUInt32(maskWord); maskWord = 0; } } // If the mask size wasn't a multiple of 32, need to write out // the final word containing the 'remainder' bits if (maskBits.size() % 32 != 0) { _records->writeUInt32(maskWord); } } } void FltExportVisitor::writeSwitch( const osg::Switch* sw ) { // An osg::Switch is just a special case of an osgSim::MultiSwitch // that only has a single mask int32 currMask = 0; int32 numMasks = 1; int32 numWordsPerMask = sw->getNumChildren() / 32; if (sw->getNumChildren() % 32 != 0) ++numWordsPerMask; uint16 length( 28 + numMasks * numWordsPerMask * sizeof(int32) ); IdHelper id(*this, sw->getName() ); _records->writeInt16( (int16) SWITCH_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt32( 0 ); // <-- 'Reserved' (unused) _records->writeInt32( currMask ); _records->writeInt32( numMasks ); _records->writeInt32( numWordsPerMask ); // Bust the mask up into as many 32-bit words as are necessary to hold it uint32 maskWord = 0; const osg::Switch::ValueList& maskBits = sw->getValueList(); for (size_t i = 0; i < maskBits.size(); ++i) { // If this bit is set, set the corresponding mask word if (maskBits[i]) maskWord |= 1 << (i % 32); // If we just set the 31st (last) bit of the current word, need // to write it out and reset prior to continuing the loop if ( (i + 1) % 32 == 0 ) { _records->writeUInt32(maskWord); maskWord = 0; } } // If the mask size wasn't a multiple of 32, need to write out // the final word containing the 'remainder' bits if (maskBits.size() % 32 != 0) { _records->writeUInt32(maskWord); } } void FltExportVisitor::writeLightPoint( const osgSim::LightPointNode* lpn ) { enum Directionality { OMNIDIRECTIONAL = 0, UNIDIRECTIONAL = 1, BIDIRECTIONAL = 2 }; enum DisplayMode { RASTER = 0, CALLIG = 1, EITHER = 2 }; enum Modes { ENABLE = 0, DISABLE = 1 }; enum Flags { NO_BACK_COLOR = 0x80000000u >> 1, CALLIGRAPHIC = 0x80000000u >> 3, REFLECTIVE = 0x80000000u >> 4, PERSPECTIVE = 0x80000000u >> 8, FLASHING = 0x80000000u >> 9, ROTATING = 0x80000000u >> 10, ROTATE_CC = 0x80000000u >> 11, VISIBLE_DAY = 0x80000000u >> 15, VISIBLE_DUSK = 0x80000000u >> 16, VISIBLE_NIGHT = 0x80000000u >> 17 }; int32 flags( NO_BACK_COLOR ); if (lpn->getNumLightPoints() == 0) return; // In OSG, each LightPoint within a LightPointNode can have different appearance // parameters, but in OpenFlight, a Light Point Record contains a list of homogeneous // vertices. To be correct, we'd have to look at all LightPoints in the LightPointNode // and spew out multiple FLT records for each group that shared common appearance // parameters. Instead, we cheat: We take the first LightPoint and use its appearance // parameters for all LightPoints in the LightPointNode. const osgSim::LightPoint& lp0 = lpn->getLightPoint( 0 ); // No really good mapping between OSG and FLT light point animations. float32 animPeriod( 0.f ); float32 animEnabled( 0.f ); float32 animPhaseDelay( 0.f ); if (lp0._blinkSequence != NULL) { flags |= FLASHING; animPeriod = 4.f; animEnabled = 2.f; animPhaseDelay = lp0._blinkSequence->getPhaseShift(); } // Note that true bidirectional light points are currently unsupported (they are unavailable // in OSG, so we never write them out to FLT as BIDIRECTIONAL. int32 directionality( OMNIDIRECTIONAL ); float32 horizLobe( 360.f ); float32 vertLobe( 360.f ); float32 lobeRoll( 0.f ); const osgSim::DirectionalSector* ds = dynamic_cast< osgSim::DirectionalSector* >( lp0._sector.get() ); if (ds) { directionality = UNIDIRECTIONAL; horizLobe = osg::RadiansToDegrees( ds->getHorizLobeAngle() ); vertLobe = osg::RadiansToDegrees( ds->getVertLobeAngle() ); lobeRoll = osg::RadiansToDegrees( ds->getLobeRollAngle() ); } { // Braces req'd to invoke idHelper destructor (and potentially // write LongID record) before Push Record. const uint16 length( 156 ); IdHelper id( *this, lpn->getName() ); _records->writeInt16( (int16) LIGHT_POINT_OP ); _records->writeInt16( length ); _records->writeID( id ); _records->writeInt16( 0 ); // Surface material code _records->writeInt16( 0 ); // Feature ID _records->writeUInt32( ~0u ); // OpenFlight erronously say -1, so will assume ~0u is OK. Back color for bidirectional _records->writeInt32( EITHER ); // Display mode _records->writeFloat32( lp0._intensity ); // Intensity _records->writeFloat32( 0.f ); // Back intensity TBD _records->writeFloat32( 0.f ); // min defocus _records->writeFloat32( 0.f ); // max defocus _records->writeInt32( DISABLE ); // Fading mode _records->writeInt32( DISABLE ); // Fog punch mode _records->writeInt32( DISABLE ); // Directional mode _records->writeInt32( 0 ); // Range mode _records->writeFloat32( lpn->getMinPixelSize() ); // min pixel size _records->writeFloat32( lpn->getMaxPixelSize() ); // max pixel size _records->writeFloat32( lp0._radius * 2.f ); // Actual size _records->writeFloat32( 1.f ); // transparent falloff pixel size _records->writeFloat32( 1.f ); // Transparent falloff exponent _records->writeFloat32( 1.f ); // Transparent falloff scalar _records->writeFloat32( 0.f ); // Transparent falloff clamp _records->writeFloat32( 1.f ); // Fog scalar _records->writeFloat32( 0.f ); // Reserved _records->writeFloat32( 0.f ); // Size difference threshold _records->writeInt32( directionality ); // Directionality _records->writeFloat32( horizLobe ); // Horizontal lobe angle _records->writeFloat32( vertLobe ); // Vertical lobe angle _records->writeFloat32( lobeRoll ); // Lobe roll angle _records->writeFloat32( 0.f ); // Directional falloff exponent _records->writeFloat32( 0.f ); // Directional ambient intensity _records->writeFloat32( animPeriod ); // Animation period in seconds _records->writeFloat32( animPhaseDelay ); // Animation phase delay in seconds _records->writeFloat32( animEnabled ); // Animation enabled period in seconds _records->writeFloat32( 1.f ); // Significance _records->writeInt32( 0 ); // Calligraphic draw order _records->writeInt32( flags ); // Flags _records->writeVec3f( osg::Vec3f( 0.f, 0.f, 0.f ) ); // Axis of rotation } { osg::ref_ptr< osg::Vec3dArray > v = new osg::Vec3dArray( lpn->getNumLightPoints() ); osg::ref_ptr< osg::Vec4Array > c = new osg::Vec4Array( lpn->getNumLightPoints() ); osg::ref_ptr< osg::Vec3Array > n = new osg::Vec3Array( lpn->getNumLightPoints() ); osg::Vec3f normal( 0.f, 0.f, 1.f ); unsigned int idx; for( idx=0; idxgetNumLightPoints(); idx++) { const osgSim::LightPoint& lp = lpn->getLightPoint( idx ); (*v)[ idx ] = lp._position; (*c)[ idx ] = lp._color; const osgSim::DirectionalSector* ds = dynamic_cast< osgSim::DirectionalSector* >( lp._sector.get() ); if (ds) normal = ds->getDirection(); (*n)[ idx ] = normal; } _vertexPalette->add( (const osg::Array*)NULL, v.get(), c.get(), n.get(), NULL, true, true, false ); } writeMatrix( lpn->getUserData() ); writeComment( *lpn ); writePush(); writeVertexList( 0, lpn->getNumLightPoints() ); writePop(); } void FltExportVisitor::writeColorPalette() { // FLT exporter doesn't use a color palette but writes // a bogus one to satisfy loaders that require it. uint16 length( 4228 ); _dos.writeInt16( (int16) COLOR_PALETTE_OP ); _dos.writeInt16( length ); _dos.writeFill( 128 ); // Reserved int idx; for( idx=0; idx<1024; idx++) _dos.writeUInt32( 0xffffffff ); // Color n } }