Files
OpenSceneGraph/src/osgPlugins/OpenFlight/expPrimaryRecords.cpp
2012-03-21 17:36:20 +00:00

795 lines
27 KiB
C++

/*
* 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 <osg/Group>
#include <osg/Sequence>
#include <osg/LightSource>
#include <osg/LOD>
#include <osg/ProxyNode>
#include <osg/Switch>
#include <osgSim/MultiSwitch>
#include <osgSim/DOFTransform>
#include <osgSim/LightPointNode>
#include <osgSim/ObjectRecordData>
#include <stdlib.h>
// 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<const ParentPools*>(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; idx<lpn->getNumLightPoints(); 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
}
}