Files
OpenSceneGraph/src/osgPlugins/OpenFlight/expPrimaryRecords.cpp
Robert Osfield 72200de866 From Katharina Plugge, "I found a bug in the OpenFlight-Plugin. When exporting to OpenFlight it could happen that palettes of an external reference like the texture palette are set wrong, because they are overwritten by parent settings (userData), which actually do not refer to palette entries respectively ParentPools (happens for example if a Transform is parent of a ProxyNode). The static cast from userData to ParentPools should therefore be a dynamic cast.
---------------------------

function FltExportVisitor::writeExternalReference( const osg::ProxyNode& proxy ):

Line 423 in file expPrimaryRecords.cpp has to be changed from

const ParentPools* pp = static_cast<const ParentPools*>(proxy.getUserData() );

to

const ParentPools* pp = dynamic_cast<const ParentPools*>(proxy.getUserData() );
"
2008-10-27 15:26:53 +00:00

794 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>
// 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::notify( 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( -1 ); // 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
}
}