Files
OpenSceneGraph/src/osgPlugins/OpenFlight/LightPointRecords.cpp
Robert Osfield 6b75603ace From Charles Cole, "Attached are mods to the OpenFlight plug-in to help further implement
the specification.  With these mods, blink sequences are now created for
flashing light point nodes, either palletized (v.15.8 and later) or
non-palletized (15.7 and earlier).  Thanks to Brede for his
implementation of the palletized light point nodes.

There is still work to do on adding the capability to properly handle
light point system nodes, but this does add some capability that did not
previously exist.  So, I wanted to at least submit this and I will
hopefully provide the additional capability in the near future.

I've tested the code modifications with Visual Studio 2005.  I don't
have the means to test any other operating system, but I would suspect
that there shouldn't be any issue (famous last words).  I used the test
files that I uploaded to the users forum to test the changes.

In addition to the added capability, I changed the light point node
radius to the "actualPixelSize" value in the file.  Previously, the
radius was set to half the actual pixel size (see
LightPointRecords.cpp).  Not sure why this was the case.  But, it was
brought to my attention by a co-worker who created the OpenFlight files
and was testing them with different viewers.  If there's some history
for setting the radius to half the size, then this change can be
omitted."
2007-05-26 15:42:30 +00:00

492 lines
16 KiB
C++

//
// OpenFlight® loader for OpenSceneGraph
//
// Copyright (C) 2005-2006 Brede Johansen
//
#include <osgSim/MultiSwitch>
#include <osgSim/LightPointSystem>
#include <osgSim/LightPointNode>
#include <osg/Texture2D>
#include "Registry.h"
#include "Document.h"
#include "RecordInputStream.h"
using namespace flt;
/** LightPoint
*/
class LightPoint : public PrimaryRecord
{
enum Directionality
{
OMNIDIRECTIONAL = 0,
UNIDIRECTIONAL = 1,
BIDIRECTIONAL = 2
};
// flags
enum Flags
{
// bit 0 = reserved
NO_BACK_COLOR = 0x80000000u >> 1, // bit 1 = no back color
// bit 2 = reserved
CALLIGRAPHIC = 0x80000000u >> 3, // bit 3 = calligraphic proximity occulting
REFLECTIVE = 0x80000000u >> 4, // bit 4 = reflective, non-emissive point
// bit 5-7 = randomize intensity
// 0 = never
// 1 = low
// 2 = medium
// 3 = high
PERSPECTIVE = 0x80000000u >> 8, // bit 8 = perspective mode
FLASHING = 0x80000000u >> 9, // bit 9 = flashing
ROTATING = 0x80000000u >> 10, // bit 10 = rotating
ROTATE_CC = 0x80000000u >> 11, // bit 11 = rotate counter clockwise
// bit 12 = reserved
// bit 13-14 = quality
// 0 = low
// 1 = medium
// 2 = high
// 3 = undefined
VISIBLE_DAY = 0x80000000u >> 15, // bit 15 = visible during day
VISIBLE_DUSK = 0x80000000u >> 16, // bit 16 = visible during dusk
VISIBLE_NIGHT = 0x80000000u >> 17 // bit 17 = visible during night
// bit 18-31 = spare
};
int16 _material;
int16 _feature;
osg::Vec4f _backColor;
int32 _displayMode;
float32 _intensityFront;
float32 _intensityBack;
float32 _minDefocus;
float32 _maxDefocus;
int32 _fadeMode;
int32 _fogPunchMode;
int32 _directionalMode;
int32 _rangeMode;
float32 _minPixelSize;
float32 _maxPixelSize;
float32 _actualPixelSize;
float32 _transparentFalloff;
float32 _transparentFalloffExponent;
float32 _transparentFalloffScalar;
float32 _transparentFalloffClamp;
float32 _fog;
float32 _sizeDifferenceThreshold;
int32 _directionality;
float32 _lobeHorizontal;
float32 _lobeVertical;
float32 _lobeRoll;
float32 _falloff;
float32 _ambientIntensity;
float32 _animationPeriod;
float32 _animationPhaseDelay;
float32 _animationPeriodEnable;
float32 _significance;
int32 _drawOrder;
uint32 _flags;
osg::Vec3f _animationAxis;
osg::ref_ptr<osgSim::LightPointNode> _lpn;
public:
LightPoint() {}
META_Record(LightPoint)
META_setID(_lpn)
META_setComment(_lpn)
META_setMatrix(_lpn)
// Add lightpoint, add two if bidirectional.
virtual void addVertex(Vertex& vertex)
{
osgSim::LightPoint lp;
lp._position = vertex._coord;
lp._radius = 0.5f * _actualPixelSize;
lp._intensity = _intensityFront;
// color
lp._color = (vertex.validColor()) ? vertex._color : osg::Vec4(1,1,1,1);
// sector
bool directional = (_directionality==UNIDIRECTIONAL) || (_directionality==BIDIRECTIONAL);
if (directional && vertex.validNormal())
{
lp._sector = new osgSim::DirectionalSector(
vertex._normal,
osg::DegreesToRadians(_lobeHorizontal),
osg::DegreesToRadians(_lobeVertical),
osg::DegreesToRadians(_lobeRoll));
}
// if the flashing or rotating bit is set in the flags, add a blink sequence
if ((_flags & FLASHING) || (_flags & ROTATING))
{
lp._blinkSequence = new osgSim::BlinkSequence();
if (lp._blinkSequence.valid())
{
lp._blinkSequence->setDataVariance(osg::Object::DYNAMIC);
lp._blinkSequence->setPhaseShift(_animationPhaseDelay);
lp._blinkSequence->addPulse(_animationPeriod - _animationPeriodEnable,
osg::Vec4f(0.0f, 0.0f, 0.0f, 0.0f));
lp._blinkSequence->addPulse(_animationPeriodEnable, lp._color);
}
}
_lpn->addLightPoint(lp);
// Create a new lightpoint if bi-directional.
if ((_directionality==BIDIRECTIONAL) && vertex.validNormal())
{
// back intensity
lp._intensity = _intensityBack;
// back color
if (!(_flags & NO_BACK_COLOR))
lp._color = _backColor;
// back sector
lp._sector = new osgSim::DirectionalSector(
-vertex._normal,
osg::DegreesToRadians(_lobeHorizontal),
osg::DegreesToRadians(_lobeVertical),
osg::DegreesToRadians(_lobeRoll));
_lpn->addLightPoint(lp);
}
}
protected:
virtual ~LightPoint() {}
virtual void readRecord(RecordInputStream& in, Document& document)
{
std::string id = in.readString(8);
_material = in.readInt16();
_feature = in.readInt16();
int32 backColorIndex = in.readInt32();
_backColor = document.getColorPool() ?
document.getColorPool()->getColor(backColorIndex) :
osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f);
_displayMode = in.readInt32();
_intensityFront = in.readFloat32();
_intensityBack = in.readFloat32();
_minDefocus = in.readFloat32();
_maxDefocus = in.readFloat32();
_fadeMode = in.readInt32();
_fogPunchMode = in.readInt32();
_directionalMode = in.readInt32();
_rangeMode = in.readInt32();
_minPixelSize = in.readFloat32(); // * document.unitScale();
_maxPixelSize = in.readFloat32(); // * document.unitScale();
_actualPixelSize = in.readFloat32(); // * document.unitScale();
_transparentFalloff = in.readFloat32();
_transparentFalloffExponent = in.readFloat32();
_transparentFalloffScalar = in.readFloat32();
_transparentFalloffClamp = in.readFloat32();
_fog = in.readFloat32();
in.forward(4);
_sizeDifferenceThreshold = in.readFloat32();
_directionality = in.readInt32();
_lobeHorizontal = in.readFloat32();
_lobeVertical = in.readFloat32();
_lobeRoll = in.readFloat32();
_falloff = in.readFloat32();
_ambientIntensity = in.readFloat32();
_animationPeriod = in.readFloat32();
_animationPhaseDelay = in.readFloat32();
_animationPeriodEnable = in.readFloat32();
_significance = in.readFloat32();
_drawOrder = in.readInt32();
_flags = in.readUInt32(0);
_animationAxis = in.readVec3f();
_lpn = new osgSim::LightPointNode;
_lpn->setName(id);
_lpn->setMinPixelSize(_minPixelSize);
_lpn->setMaxPixelSize(_maxPixelSize);
// Add to parent
if (_parent.valid())
_parent->addChild(*_lpn);
}
};
RegisterRecordProxy<LightPoint> g_LightPoint(LIGHT_POINT_OP);
/** IndexedLightPoint
*/
class IndexedLightPoint : public PrimaryRecord
{
enum Directionality
{
OMNIDIRECTIONAL = 0,
UNIDIRECTIONAL = 1,
BIDIRECTIONAL = 2
};
// flags
static const unsigned int NO_BACK_COLOR_BIT = 0x80000000u >> 1;
osg::ref_ptr<osgSim::LightPointNode> _lpn;
osg::ref_ptr<LPAppearance> _appearance;
osg::ref_ptr<LPAnimation> _animation;
public:
IndexedLightPoint() {}
META_Record(IndexedLightPoint)
META_setID(_lpn)
META_setComment(_lpn)
META_setMatrix(_lpn)
// Add lightpoint, add two if bidirectional.
virtual void addVertex(Vertex& vertex)
{
osgSim::LightPoint lp;
if (_appearance.valid())
{
lp._position = vertex._coord;
lp._radius = 0.5f * _appearance->actualPixelSize;
lp._intensity = _appearance->intensityFront;
// color
lp._color = (vertex.validColor()) ? vertex._color : osg::Vec4(1,1,1,1);
// sector
bool directional = (_appearance->directionality==UNIDIRECTIONAL) || (_appearance->directionality==BIDIRECTIONAL);
if (directional && vertex.validNormal())
{
lp._sector = new osgSim::DirectionalSector(
vertex._normal,
osg::DegreesToRadians(_appearance->horizontalLobeAngle),
osg::DegreesToRadians(_appearance->verticalLobeAngle),
osg::DegreesToRadians(_appearance->lobeRollAngle));
}
// Blink sequence
if (_animation.valid())
{
osgSim::BlinkSequence* blinkSequence = new osgSim::BlinkSequence;
blinkSequence->setName(_animation->name);
switch (_animation->animationType)
{
case LPAnimation::ROTATING:
case LPAnimation::STROBE:
blinkSequence->setPhaseShift(_animation->animationPhaseDelay);
blinkSequence->addPulse(_animation->animationPeriod-_animation->animationEnabledPeriod, osg::Vec4(0,0,0,0));
blinkSequence->addPulse(_animation->animationEnabledPeriod, lp._color);
break;
case LPAnimation::MORSE_CODE:
// todo
//blinkSequence->addPulse(double length,lp._color);
break;
case LPAnimation::FLASHING_SEQUENCE:
{
blinkSequence->setPhaseShift(_animation->animationPhaseDelay);
for (LPAnimation::PulseArray::iterator itr=_animation->sequence.begin();
itr!=_animation->sequence.end();
++itr)
{
double duration = itr->duration;
osg::Vec4 color;
switch (itr->state)
{
case LPAnimation::ON:
color = lp._color;
break;
case LPAnimation::OFF:
color = osg::Vec4(0,0,0,0);
break;
case LPAnimation::COLOR_CHANGE:
color = itr->color;
break;
}
blinkSequence->addPulse(duration, color);
}
}
break;
}
lp._blinkSequence = blinkSequence;
}
_lpn->addLightPoint(lp);
// Create a new lightpoint if bi-directional.
if ((_appearance->directionality==BIDIRECTIONAL) && vertex.validNormal())
{
// back intensity
lp._intensity = _appearance->intensityBack;
// back color
if (!(_appearance->flags & NO_BACK_COLOR_BIT))
lp._color = _appearance->backColor;
// back sector
lp._sector = new osgSim::DirectionalSector(
-vertex._normal,
osg::DegreesToRadians(_appearance->horizontalLobeAngle),
osg::DegreesToRadians(_appearance->verticalLobeAngle),
osg::DegreesToRadians(_appearance->lobeRollAngle));
_lpn->addLightPoint(lp);
}
}
}
protected:
virtual ~IndexedLightPoint() {}
virtual void readRecord(RecordInputStream& in, Document& document)
{
std::string id = in.readString(8);
int32 appearanceIndex = in.readInt32();
int32 animationIndex = in.readInt32();
int32 drawOrder = in.readInt32(); // for calligraphic lights
LightPointAppearancePool* lpAppearancePool = document.getOrCreateLightPointAppearancePool();
_appearance = lpAppearancePool->get(appearanceIndex);
LightPointAnimationPool* lpAnimationPool = document.getOrCreateLightPointAnimationPool();
_animation = lpAnimationPool->get(animationIndex);
_lpn = new osgSim::LightPointNode;
_lpn->setName(id);
if (_appearance.valid())
{
_lpn->setMinPixelSize(_appearance->minPixelSize);
_lpn->setMaxPixelSize(_appearance->maxPixelSize);
if (_appearance->texturePatternIndex != -1)
{
// Use point sprites for light points.
_lpn->setPointSprite();
TexturePool* tp = document.getOrCreateTexturePool();
osg::StateSet* textureStateSet = tp->get(_appearance->texturePatternIndex);
if (textureStateSet)
{
// Merge face stateset with texture stateset
osg::StateSet* stateset = _lpn->getOrCreateStateSet();
stateset->merge(*textureStateSet);
}
}
}
// Add to parent
if (_parent.valid())
_parent->addChild(*_lpn);
}
};
RegisterRecordProxy<IndexedLightPoint> g_IndexedLightPoint(INDEXED_LIGHT_POINT_OP);
/** LightPointSystem
*/
class LightPointSystem : public PrimaryRecord
{
float32 _intensity;
int32 _animationState;
int32 _flags;
osg::ref_ptr<osgSim::MultiSwitch> _switch;
osg::ref_ptr<osgSim::LightPointSystem> _lps;
public:
LightPointSystem():
_intensity(1.0f),
_animationState(0),
_flags(0)
{}
META_Record(LightPointSystem)
META_addChild(_switch)
protected:
virtual ~LightPointSystem() {}
virtual void readRecord(RecordInputStream& in, Document& document)
{
std::string id = in.readString(8);
_intensity = in.readFloat32();
_animationState = in.readInt32(0);
_flags = in.readInt32(0);
_switch = new osgSim::MultiSwitch;
_lps = new osgSim::LightPointSystem;
_switch->setName(id);
_lps->setName(id);
_lps->setIntensity(_intensity);
switch (_animationState)
{
// Note that OpenFlight 15.8 spec says 0 means on and 1 means off.
// However, if animation is set on in Creator, it stores a 1, and
// a zero is stored for off! So, for now, we ignore the spec...
case 0:
_lps->setAnimationState( osgSim::LightPointSystem::ANIMATION_OFF );
break;
default:
case 1:
_lps->setAnimationState( osgSim::LightPointSystem::ANIMATION_ON );
break;
case 2:
_lps->setAnimationState( osgSim::LightPointSystem::ANIMATION_RANDOM );
break;
}
if (_parent.valid())
_parent->addChild(*((osg::Group*)_switch.get()));
}
virtual void popLevel(Document& document)
{
// Set default sets: 0 for all off, 1 for all on
_switch->setAllChildrenOff( 0 );
_switch->setAllChildrenOn( 1 );
// set initial on/off state
unsigned int initialSet = ( (_flags & 0x80000000) != 0 ) ? 1 : 0;
_switch->setActiveSwitchSet( initialSet );
for (unsigned int i = 0; i < _switch->getNumChildren(); i++)
{
osg::Node* child = _switch->getChild(i);
if (osgSim::LightPointNode* lpn = dynamic_cast<osgSim::LightPointNode*>(child))
lpn->setLightPointSystem(_lps.get());
}
}
};
RegisterRecordProxy<LightPointSystem> g_LightPointSystem(LIGHT_POINT_SYSTEM_OP);