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."
492 lines
16 KiB
C++
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);
|
|
|