1068 lines
32 KiB
C++
1068 lines
32 KiB
C++
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
|
|
*
|
|
* 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 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.
|
|
*/
|
|
|
|
//
|
|
// OpenFlight® loader for OpenSceneGraph
|
|
//
|
|
// Copyright (C) 2005-2007 Brede Johansen
|
|
//
|
|
|
|
#include <assert.h>
|
|
#include <typeinfo>
|
|
#include <osg/Notify>
|
|
#include <osg/ShadeModel>
|
|
#include <osg/ProxyNode>
|
|
#include <osg/Sequence>
|
|
#include <osg/LOD>
|
|
#include <osg/ProxyNode>
|
|
#include <osg/LightSource>
|
|
#include <osgDB/FileUtils>
|
|
#include <osgSim/DOFTransform>
|
|
#include <osgSim/MultiSwitch>
|
|
#include <osgSim/GeographicLocation>
|
|
#include <osgSim/ObjectRecordData>
|
|
|
|
#include <osg/Notify>
|
|
#include <osg/io_utils>
|
|
|
|
#include "Registry.h"
|
|
#include "Document.h"
|
|
#include "RecordInputStream.h"
|
|
|
|
namespace flt {
|
|
|
|
/** Header
|
|
*/
|
|
class Header : public PrimaryRecord
|
|
{
|
|
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;
|
|
|
|
osg::ref_ptr<osg::Group> _header;
|
|
|
|
public:
|
|
|
|
Header() {}
|
|
|
|
META_Record(Header)
|
|
|
|
META_setID(_header)
|
|
META_setComment(_header)
|
|
META_setMultitexture(_header)
|
|
META_addChild(_header)
|
|
|
|
protected:
|
|
|
|
virtual ~Header() {}
|
|
|
|
virtual void readRecord(RecordInputStream& in, Document& document)
|
|
{
|
|
std::string id = in.readString(8);
|
|
OSG_DEBUG << "ID: " << id << std::endl;
|
|
|
|
uint32 format = in.readUInt32();
|
|
OSG_DEBUG << "Format: " << format << std::endl;
|
|
document._version = format;
|
|
|
|
/*uint32 revision =*/ in.readUInt32();
|
|
|
|
std::string revisionTime = in.readString(32);
|
|
OSG_INFO << "Last revision: " << revisionTime << std::endl;
|
|
|
|
in.forward(4*2);
|
|
|
|
// Flight v.11 & 12 use integer coordinates
|
|
int16 multDivUnits = in.readInt16(); // Units multiplier/divisor
|
|
uint8 units = in.readUInt8(); // 0=Meters 1=Kilometers 4=Feet 5=Inches 8=Nautical miles
|
|
/*uint8 textureWhite =*/ in.readUInt8();
|
|
/*uint32 flags =*/ in.readUInt32();
|
|
|
|
in.forward( 4*6 );
|
|
/*int32 projectionType =*/ in.readInt32();
|
|
|
|
in.forward( 4*7 );
|
|
/*int16 nextDOF =*/ in.readInt16();
|
|
/*int16 vertStorage =*/ in.readInt16();
|
|
/*int32 dbOrigin =*/ in.readInt32();
|
|
|
|
/*float64 swX =*/ in.readFloat64();
|
|
/*float64 swY =*/ in.readFloat64();
|
|
/*float64 deltaX =*/ in.readFloat64();
|
|
/*float64 deltaY =*/ in.readFloat64();
|
|
|
|
in.forward( 2*2 ); /* some "next bead" IDs */
|
|
in.forward( 4*2 ); /* reserved */
|
|
in.forward( 4*2 ); /* more "next bead" IDs */
|
|
in.forward( 4 ); /* reserved */
|
|
|
|
/*float64 swLat =*/ in.readFloat64();
|
|
/*float64 swLong =*/ in.readFloat64();
|
|
/*float64 neLat =*/ in.readFloat64();
|
|
/*float64 neLong =*/ in.readFloat64();
|
|
float64 originLat = in.readFloat64();
|
|
float64 originLong = in.readFloat64();
|
|
|
|
if (document.getDoUnitsConversion())
|
|
document._unitScale = unitsToMeters((CoordUnits)units) / unitsToMeters(document.getDesiredUnits());
|
|
|
|
if (document._version < VERSION_13)
|
|
{
|
|
if (multDivUnits >= 0)
|
|
document._unitScale *= (double)multDivUnits;
|
|
else
|
|
document._unitScale /= (double)(-multDivUnits);
|
|
}
|
|
|
|
_header = new osg::Group;
|
|
_header->setName(id);
|
|
|
|
// Store model origin in returned Node userData.
|
|
osgSim::GeographicLocation* loc = new osgSim::GeographicLocation;
|
|
loc->set( originLat, originLong );
|
|
_header->setUserData( loc );
|
|
OSG_INFO << "DB lat=" << originLat << " lon=" << originLong << std::endl;
|
|
|
|
document.setHeaderNode(_header.get());
|
|
}
|
|
|
|
virtual void dispose(Document& document)
|
|
{
|
|
if (_header.valid())
|
|
{
|
|
// Preset sampler uniforms.
|
|
ShaderPool* sp = document.getShaderPool();
|
|
if (sp && !sp->empty())
|
|
{
|
|
_header->getOrCreateStateSet()->addUniform( new osg::Uniform("TextureUnit0", 0) );
|
|
_header->getOrCreateStateSet()->addUniform( new osg::Uniform("TextureUnit1", 1) );
|
|
_header->getOrCreateStateSet()->addUniform( new osg::Uniform("TextureUnit2", 2) );
|
|
_header->getOrCreateStateSet()->addUniform( new osg::Uniform("TextureUnit3", 3) );
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
REGISTER_FLTRECORD(Header, HEADER_OP)
|
|
|
|
|
|
/** Group
|
|
*/
|
|
class Group : public PrimaryRecord
|
|
{
|
|
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;
|
|
|
|
osg::ref_ptr<osg::Group> _group;
|
|
uint32 _flags;
|
|
bool _forwardAnim;
|
|
bool _backwardAnim;
|
|
int32 _loopCount;
|
|
float32 _loopDuration;
|
|
float32 _lastFrameDuration;
|
|
|
|
public:
|
|
|
|
Group():
|
|
_flags(0),
|
|
_forwardAnim(false),
|
|
_backwardAnim(false),
|
|
_loopCount(0),
|
|
_loopDuration(0),
|
|
_lastFrameDuration(0)
|
|
{}
|
|
|
|
META_Record(Group)
|
|
|
|
META_setID(_group)
|
|
META_setComment(_group)
|
|
META_setMultitexture(_group)
|
|
META_addChild(_group)
|
|
|
|
bool hasAnimation() const { return _forwardAnim || _backwardAnim; }
|
|
|
|
protected:
|
|
|
|
void readRecord(RecordInputStream& in, Document& document)
|
|
{
|
|
std::string id = in.readString(8);
|
|
OSG_DEBUG << "ID: " << id << std::endl;
|
|
|
|
/*int16 relativePriority =*/ in.readInt16();
|
|
in.forward(2);
|
|
_flags = in.readUInt32(0);
|
|
/*uint16 specialId0 =*/ in.readUInt16();
|
|
/*uint16 specialId1 =*/ in.readUInt16();
|
|
/*uint16 significance =*/ in.readUInt16();
|
|
/*int8 layer =*/ in.readInt8();
|
|
in.forward(5);
|
|
// version >= VERSION_15_8
|
|
_loopCount = in.readInt32(0);
|
|
_loopDuration = in.readFloat32(0.0f);
|
|
_lastFrameDuration = in.readFloat32(0.0f);
|
|
|
|
// Check for forward animation (sequence)
|
|
_forwardAnim = (_flags & FORWARD_ANIM) != 0;
|
|
|
|
// For versions prior to 15.8, the swing bit can be set independently
|
|
// of the animation bit. This implies forward animation (with swing)
|
|
if ((document.version() < VERSION_15_8) && (_flags & SWING_ANIM))
|
|
_forwardAnim = true;
|
|
|
|
// OpenFlight 15.8 adds backwards animations
|
|
_backwardAnim = ( (document.version() >= VERSION_15_8) &&
|
|
((_flags & BACKWARD_ANIM) != 0) );
|
|
|
|
if (_forwardAnim || _backwardAnim)
|
|
_group = new osg::Sequence;
|
|
else
|
|
_group = new osg::Group;
|
|
|
|
_group->setName(id);
|
|
|
|
// Add this implementation to parent implementation.
|
|
if (_parent.valid())
|
|
_parent->addChild(*_group);
|
|
}
|
|
|
|
virtual void dispose(Document& document)
|
|
{
|
|
if (!_group.valid()) return;
|
|
|
|
// Insert transform(s)
|
|
if (_matrix.valid())
|
|
{
|
|
insertMatrixTransform(*_group,*_matrix,_numberOfReplications);
|
|
}
|
|
|
|
// Children are added!
|
|
osg::Sequence* sequence = dynamic_cast<osg::Sequence*>(_group.get());
|
|
if (sequence && sequence->getNumChildren() > 0)
|
|
{
|
|
// Regardless of forwards or backwards, animation could have swing bit set.
|
|
osg::Sequence::LoopMode loopMode = ((_flags & SWING_ANIM) == 0) ?
|
|
osg::Sequence::LOOP : osg::Sequence::SWING;
|
|
|
|
if (_forwardAnim)
|
|
sequence->setInterval(loopMode, 0, -1);
|
|
else
|
|
sequence->setInterval(loopMode, -1, 0);
|
|
|
|
// Loop timing available from version 15.8.
|
|
if (document.version() >= VERSION_15_8)
|
|
{
|
|
// Set frame duration.
|
|
float frameDuration = _loopDuration / float(sequence->getNumChildren());
|
|
for (unsigned int i=0; i < sequence->getNumChildren(); i++)
|
|
sequence->setTime(i, frameDuration);
|
|
|
|
// Set number of repetitions.
|
|
if (_loopCount > 0)
|
|
sequence->setDuration(1.0f, _loopCount);
|
|
else
|
|
sequence->setDuration(1.0f); // Run continuously
|
|
}
|
|
else // No timing available.
|
|
{
|
|
// Set frame duration
|
|
float frameDuration = 0.1f; // 10Hz
|
|
for (unsigned int i=0; i < sequence->getNumChildren(); i++)
|
|
sequence->setTime(i, frameDuration);
|
|
|
|
// Run continuously
|
|
sequence->setDuration(1.0f);
|
|
}
|
|
|
|
sequence->setMode(osg::Sequence::START);
|
|
}
|
|
}
|
|
};
|
|
|
|
REGISTER_FLTRECORD(Group, GROUP_OP)
|
|
|
|
|
|
|
|
/** DegreeOfFreedom
|
|
*/
|
|
class DegreeOfFreedom : public PrimaryRecord
|
|
{
|
|
// Flags
|
|
static const unsigned long LIMIT_TRANSLATION_X = 0x80000000u >> 0;
|
|
static const unsigned long LIMIT_TRANSLATION_Y = 0x80000000u >> 1;
|
|
static const unsigned long LIMIT_TRANSLATION_Z = 0x80000000u >> 2;
|
|
static const unsigned long LIMIT_PITCH = 0x80000000u >> 3;
|
|
static const unsigned long LIMIT_ROLL = 0x80000000u >> 4;
|
|
static const unsigned long LIMIT_YAW = 0x80000000u >> 5;
|
|
static const unsigned long LIMIT_SCALE_X = 0x80000000u >> 6;
|
|
static const unsigned long LIMIT_SCALE_Y = 0x80000000u >> 7;
|
|
static const unsigned long LIMIT_SCALE_Z = 0x80000000u >> 8;
|
|
|
|
struct Range
|
|
{
|
|
float64 min; // Minimum value with respect to the local coord system
|
|
float64 max; // Maximum value with respect to the local coord system
|
|
float64 current; // Current value with respect to the local coord system
|
|
float64 increment; // Increment
|
|
};
|
|
|
|
osg::ref_ptr<osgSim::DOFTransform> _dof;
|
|
|
|
public:
|
|
|
|
DegreeOfFreedom():
|
|
_dof(new osgSim::DOFTransform) {}
|
|
|
|
META_Record(DegreeOfFreedom)
|
|
|
|
META_setID(_dof)
|
|
META_setComment(_dof)
|
|
META_setMultitexture(_dof)
|
|
META_addChild(_dof)
|
|
META_dispose(_dof)
|
|
|
|
protected:
|
|
|
|
virtual ~DegreeOfFreedom() {}
|
|
virtual void readRecord(RecordInputStream& in, Document& document)
|
|
{
|
|
std::string id = in.readString(8);
|
|
in.forward(4); // Reserved
|
|
osg::Vec3d localOrigin = in.readVec3d();
|
|
osg::Vec3d pointOnXAxis = in.readVec3d();
|
|
osg::Vec3d pointInXYPlane = in.readVec3d();
|
|
Range rangeZ = readRange(in); // Legal z values with respect to the local coord system
|
|
Range rangeY = readRange(in); // Legal y values with respect to the local coord system
|
|
Range rangeX = readRange(in); // Legal x values with respect to the local coord system
|
|
Range rangePitch = readRange(in); // Legal pitch values (rotation about the x-axis)
|
|
Range rangeRoll = readRange(in); // Legal roll values( rotation about the y-axis)
|
|
Range rangeYaw = readRange(in); // Legal yaw values (rotation about the z-axis)
|
|
Range rangeScaleZ = readRange(in); // Legal z scale values (about local origin)
|
|
Range rangeScaleY = readRange(in); // Legal y scale values about local origin)
|
|
Range rangeScaleX = readRange(in); // Legal x scale values (about local origin)
|
|
uint32 flags = in.readUInt32(); // Flags, bits from left to right (see OF doc)
|
|
|
|
// out of range check, required for racecar.flt (Creator Gallery)
|
|
if (!valid(localOrigin))
|
|
localOrigin = osg::Vec3d(0,0,0);
|
|
if (!valid(pointOnXAxis))
|
|
pointOnXAxis = osg::X_AXIS;
|
|
if (!valid(pointInXYPlane))
|
|
pointInXYPlane = osg::Y_AXIS;
|
|
|
|
_dof->setName(id);
|
|
|
|
//tranlsations:
|
|
_dof->setMinTranslate(osg::Vec3(rangeX.min,rangeY.min,rangeZ.min)*document.unitScale());
|
|
_dof->setMaxTranslate(osg::Vec3(rangeX.max,rangeY.max,rangeZ.max)*document.unitScale());
|
|
_dof->setCurrentTranslate(osg::Vec3(rangeX.current,rangeY.current,rangeZ.current)*document.unitScale());
|
|
_dof->setIncrementTranslate(osg::Vec3(rangeX.increment,rangeY.increment,rangeZ.increment)*document.unitScale());
|
|
|
|
//rotations:
|
|
_dof->setMinHPR(osg::Vec3(osg::inDegrees(rangeYaw.min),osg::inDegrees(rangePitch.min),osg::inDegrees(rangeRoll.min)));
|
|
_dof->setMaxHPR(osg::Vec3(osg::inDegrees(rangeYaw.max),osg::inDegrees(rangePitch.max),osg::inDegrees(rangeRoll.max)));
|
|
_dof->setCurrentHPR(osg::Vec3(osg::inDegrees(rangeYaw.current),osg::inDegrees(rangePitch.current),osg::inDegrees(rangeRoll.current)));
|
|
_dof->setIncrementHPR(osg::Vec3(osg::inDegrees(rangeYaw.increment),osg::inDegrees(rangePitch.increment),osg::inDegrees(rangeRoll.increment)));
|
|
|
|
//scales:
|
|
_dof->setMinScale(osg::Vec3(rangeScaleX.min,rangeScaleY.min,rangeScaleZ.min));
|
|
_dof->setMaxScale(osg::Vec3(rangeScaleX.max,rangeScaleY.max,rangeScaleZ.max));
|
|
_dof->setCurrentScale(osg::Vec3(rangeScaleX.current,rangeScaleY.current,rangeScaleZ.current));
|
|
_dof->setIncrementScale(osg::Vec3(rangeScaleX.increment,rangeScaleY.increment,rangeScaleZ.increment));
|
|
|
|
// compute axis.
|
|
osg::Vec3 xAxis = pointOnXAxis - localOrigin;
|
|
osg::Vec3 xyPlaneVector = pointInXYPlane - localOrigin;
|
|
osg::Vec3 zAxis = xAxis ^ xyPlaneVector;
|
|
osg::Vec3 yAxis = zAxis ^ xAxis;
|
|
|
|
// normalize
|
|
float length_x = xAxis.normalize();
|
|
float length_y = yAxis.normalize();
|
|
float length_z = zAxis.normalize();
|
|
|
|
if ((length_x*length_y*length_z)==0.0f)
|
|
{
|
|
OSG_NOTICE<<"Warning: OpenFlight DegreeOfFreedom::readRecord() found erroneous axis definition:"<<std::endl;
|
|
OSG_NOTICE<<" localOrigin="<<localOrigin<<std::endl;
|
|
OSG_NOTICE<<" pointOnXAxis="<<pointOnXAxis<<std::endl;
|
|
OSG_NOTICE<<" pointInXYPlane="<<pointInXYPlane<<std::endl;
|
|
|
|
xAxis.set(1.0f,0.0f,0.0f);
|
|
yAxis.set(0.0f,1.0f,0.0f);
|
|
zAxis.set(0.0f,0.0f,1.0f);
|
|
}
|
|
|
|
// scale origin
|
|
osg::Vec3 origin = localOrigin * document.unitScale();
|
|
|
|
// create putmatrix
|
|
osg::Matrix inv_putmat(xAxis.x(), xAxis.y(), xAxis.z(), 0.0,
|
|
yAxis.x(), yAxis.y(), yAxis.z(), 0.0,
|
|
zAxis.x(), zAxis.y(), zAxis.z(), 0.0,
|
|
origin.x(), origin.y(), origin.z(), 1.0);
|
|
|
|
|
|
_dof->setInversePutMatrix(inv_putmat);
|
|
_dof->setPutMatrix(osg::Matrix::inverse(inv_putmat));
|
|
|
|
_dof->setLimitationFlags(flags);
|
|
_dof->setAnimationOn(document.getDefaultDOFAnimationState());
|
|
// _dof->setHPRMultOrder(osgSim::DOFTransform::HPR);
|
|
|
|
// Add this implementation to parent implementation.
|
|
if (_parent.valid())
|
|
_parent->addChild(*_dof);
|
|
}
|
|
|
|
Range readRange(RecordInputStream& in) const
|
|
{
|
|
Range range;
|
|
range.min = in.readFloat64();
|
|
range.max = in.readFloat64();
|
|
range.current = in.readFloat64();
|
|
range.increment = in.readFloat64();
|
|
|
|
// Extend valid range (See Creator help on DOF).
|
|
if (range.current < range.min) range.min = range.current;
|
|
if (range.current > range.max) range.max = range.current;
|
|
|
|
const float64 epsilon = 1.0e-7;
|
|
if (fabs(range.max-range.min) < epsilon)
|
|
range.increment = 0;
|
|
|
|
return range;
|
|
}
|
|
|
|
bool valid(const osg::Vec3d& v) const
|
|
{
|
|
const osg::Vec3d bad(-1.0e8,-1.0e8,-1.0e8);
|
|
const float64 epsilon = 1.0e-7;
|
|
|
|
return (fabs(v.x()-bad.x()) > epsilon) ||
|
|
(fabs(v.y()-bad.y()) > epsilon) ||
|
|
(fabs(v.z()-bad.z()) > epsilon);
|
|
}
|
|
};
|
|
|
|
REGISTER_FLTRECORD(DegreeOfFreedom, DOF_OP)
|
|
|
|
|
|
|
|
/** LevelOfDetail - To recreate the LevelOfDetail record in OSG we have to create a LOD node with one Group node under it.
|
|
* OSG representation Children of the LevelOfDetail record will be added to
|
|
*/
|
|
class LevelOfDetail : public PrimaryRecord
|
|
{
|
|
osg::ref_ptr<osg::LOD> _lod;
|
|
osg::ref_ptr<osg::Group> _impChild0;
|
|
|
|
public:
|
|
|
|
LevelOfDetail() {}
|
|
|
|
META_Record(LevelOfDetail)
|
|
|
|
META_setID(_lod)
|
|
META_setComment(_lod)
|
|
META_setMultitexture(_lod)
|
|
META_addChild(_impChild0)
|
|
META_dispose(_lod)
|
|
|
|
protected:
|
|
|
|
virtual ~LevelOfDetail() {}
|
|
virtual void readRecord(RecordInputStream& in, Document& document)
|
|
{
|
|
std::string id = in.readString(8);
|
|
in.forward(4);
|
|
float64 switchInDistance = in.readFloat64();
|
|
float64 switchOutDistance = in.readFloat64();
|
|
/*int16 specialEffectID1 =*/ in.readInt16();
|
|
/*int16 specialEffectID2 =*/ in.readInt16();
|
|
/*uint32 flags =*/ in.readUInt32();
|
|
osg::Vec3d center = in.readVec3d();
|
|
|
|
_lod = new osg::LOD;
|
|
_lod->setName(id);
|
|
_lod->setCenter(center*document.unitScale());
|
|
|
|
_impChild0 = new osg::Group;
|
|
_impChild0->setName("LOD child0");
|
|
|
|
// Add child to lod.
|
|
_lod->addChild(_impChild0.get(),
|
|
(float)switchOutDistance * document.unitScale(),
|
|
(float)switchInDistance * document.unitScale());
|
|
|
|
// Add this implementation to parent implementation.
|
|
if (_parent.valid())
|
|
_parent->addChild(*_lod);
|
|
}
|
|
|
|
};
|
|
|
|
REGISTER_FLTRECORD(LevelOfDetail, LOD_OP)
|
|
|
|
|
|
|
|
/** OldLevelOfDetail
|
|
*/
|
|
class OldLevelOfDetail : public PrimaryRecord
|
|
{
|
|
osg::ref_ptr<osg::LOD> _lod;
|
|
osg::ref_ptr<osg::Group> _impChild0;
|
|
|
|
public:
|
|
|
|
OldLevelOfDetail() {}
|
|
|
|
META_Record(OldLevelOfDetail)
|
|
|
|
META_setID(_lod)
|
|
META_setComment(_lod)
|
|
META_setMultitexture(_lod)
|
|
META_addChild(_impChild0)
|
|
META_dispose(_lod)
|
|
|
|
protected:
|
|
|
|
virtual ~OldLevelOfDetail() {}
|
|
virtual void readRecord(RecordInputStream& in, Document& document)
|
|
{
|
|
std::string id = in.readString(8);
|
|
uint32 switchInDistance = in.readUInt32();
|
|
uint32 switchOutDistance = in.readUInt32();
|
|
/*int16 specialEffectID1 =*/ in.readInt16();
|
|
/*int16 specialEffectID2 =*/ in.readInt16();
|
|
/*uint32 flags =*/ in.readUInt32();
|
|
|
|
osg::Vec3 center;
|
|
center.x() = (float)in.readInt32();
|
|
center.y() = (float)in.readInt32();
|
|
center.z() = (float)in.readInt32();
|
|
|
|
_lod = new osg::LOD;
|
|
_lod->setName(id);
|
|
_lod->setCenter(center*document.unitScale());
|
|
_lod->setRange(0, (float)switchOutDistance * document.unitScale(),
|
|
(float)switchInDistance * document.unitScale());
|
|
|
|
// Add child to lod.
|
|
_impChild0 = new osg::Group;
|
|
_lod->addChild(_impChild0.get());
|
|
|
|
// Add this implementation to parent implementation.
|
|
if (_parent.valid())
|
|
_parent->addChild(*_lod);
|
|
}
|
|
|
|
};
|
|
|
|
REGISTER_FLTRECORD(OldLevelOfDetail, OLD_LOD_OP)
|
|
|
|
|
|
|
|
/** Switch
|
|
*/
|
|
class Switch : public PrimaryRecord
|
|
{
|
|
uint32 _currentMask;
|
|
uint32 _numberOfMasks;
|
|
uint32 _wordsInMask;
|
|
std::vector<uint32> _masks;
|
|
|
|
osg::ref_ptr<osgSim::MultiSwitch> _multiSwitch;
|
|
|
|
public:
|
|
|
|
Switch() {}
|
|
|
|
META_Record(Switch)
|
|
|
|
META_setID(_multiSwitch)
|
|
META_setComment(_multiSwitch)
|
|
META_setMultitexture(_multiSwitch)
|
|
META_dispose(_multiSwitch)
|
|
|
|
virtual void addChild(osg::Node& child)
|
|
{
|
|
if (_multiSwitch.valid())
|
|
{
|
|
unsigned int nChild = _multiSwitch->getNumChildren();
|
|
for (unsigned int nMask=0; nMask<_numberOfMasks; ++nMask)
|
|
{
|
|
// test if this child is active in the current mask (itMask)
|
|
unsigned int nMaskBit = nChild % 32;
|
|
unsigned int nMaskWord = nMask * _wordsInMask + nChild / 32;
|
|
_multiSwitch->setValue(nMask, nChild, (_masks[nMaskWord] & (uint32(1) << nMaskBit))!=0 );
|
|
}
|
|
|
|
_multiSwitch->addChild(&child);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
|
|
virtual ~Switch() {}
|
|
virtual void readRecord(RecordInputStream& in, Document& /*document*/)
|
|
{
|
|
std::string id = in.readString(8);
|
|
in.forward(4);
|
|
_currentMask = in.readUInt32();
|
|
_numberOfMasks = in.readUInt32();
|
|
_wordsInMask = in.readUInt32();
|
|
|
|
_multiSwitch = new osgSim::MultiSwitch;
|
|
_multiSwitch->setName(id);
|
|
|
|
/* Example:
|
|
| word #0 || word #1 || word #2 | <- Mask #0
|
|
| word #0 || word #1 || word #2 | <- Mask #1
|
|
In this example numberOfMasks=2 and wordsInMask=3, currentMask can be 0 or 1.
|
|
*/
|
|
|
|
for (unsigned int n=0; n<_numberOfMasks*_wordsInMask; n++)
|
|
{
|
|
uint32 maskWord = in.readUInt32();
|
|
_masks.push_back(maskWord);
|
|
}
|
|
|
|
_multiSwitch->setActiveSwitchSet(_currentMask);
|
|
|
|
// Add this implementation to parent implementation.
|
|
if (_parent.valid())
|
|
_parent->addChild(*_multiSwitch);
|
|
}
|
|
};
|
|
|
|
REGISTER_FLTRECORD(Switch, SWITCH_OP)
|
|
|
|
|
|
|
|
/** ExternalReference
|
|
*/
|
|
class ExternalReference : public PrimaryRecord
|
|
{
|
|
osg::ref_ptr<osg::ProxyNode> _external;
|
|
|
|
// 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;
|
|
|
|
public:
|
|
|
|
ExternalReference() {}
|
|
|
|
META_Record(ExternalReference)
|
|
|
|
META_setID(_external)
|
|
META_setComment(_external)
|
|
META_setMultitexture(_external)
|
|
META_addChild(_external)
|
|
META_dispose(_external)
|
|
|
|
protected:
|
|
|
|
virtual ~ExternalReference() {}
|
|
virtual void readRecord(RecordInputStream& in, Document& document)
|
|
{
|
|
std::string strFile = in.readString(200);
|
|
|
|
_external = new osg::ProxyNode;
|
|
_external->setCenterMode(osg::ProxyNode::USE_BOUNDING_SPHERE_CENTER);
|
|
_external->setFileName(0,strFile);
|
|
|
|
// Set parent pools as user data
|
|
if (document.version() >= VERSION_14_2)
|
|
{
|
|
in.forward(4);
|
|
|
|
uint32 mask = in.readUInt32(~0u);
|
|
|
|
// Possible bug in models with version number 15.4.1 ?
|
|
// Symptoms: Black trees in VegaPlayer town.
|
|
if (document.version() == 1541)
|
|
mask = ~0u;
|
|
|
|
ParentPools* parentPools = new ParentPools;
|
|
|
|
if ((mask & COLOR_PALETTE_OVERRIDE) == 0)
|
|
parentPools->setColorPool(document.getColorPool());
|
|
|
|
if ((mask & MATERIAL_PALETTE_OVERRIDE) == 0)
|
|
parentPools->setMaterialPool(document.getMaterialPool());
|
|
|
|
if ((mask & TEXTURE_PALETTE_OVERRIDE) == 0)
|
|
parentPools->setTexturePool(document.getTexturePool());
|
|
|
|
if ((document.version() >= VERSION_15_1) && ((mask & LIGHT_SOURCE_PALETTE_OVERRIDE) == 0))
|
|
parentPools->setLightSourcePool(document.getLightSourcePool());
|
|
|
|
if ((document.version() >= VERSION_15_8) && ((mask & LIGHT_POINT_PALETTE_OVERRIDE) == 0))
|
|
parentPools->setLPAppearancePool(document.getLightPointAppearancePool());
|
|
|
|
if ((document.version() >= VERSION_16_0) && ((mask & SHADER_PALETTE_OVERRIDE) == 0))
|
|
parentPools->setShaderPool(document.getShaderPool());
|
|
|
|
_external->setUserData(parentPools);
|
|
}
|
|
|
|
// Add this implementation to parent implementation.
|
|
if (_parent.valid())
|
|
_parent->addChild(*_external);
|
|
}
|
|
|
|
};
|
|
|
|
REGISTER_FLTRECORD(ExternalReference, EXTERNAL_REFERENCE_OP)
|
|
|
|
|
|
|
|
/** InstanceDefinition
|
|
*/
|
|
class InstanceDefinition : public PrimaryRecord
|
|
{
|
|
int _number;
|
|
osg::ref_ptr<osg::Group> _instanceDefinition;
|
|
|
|
public:
|
|
|
|
InstanceDefinition():_number(0) {}
|
|
|
|
META_Record(InstanceDefinition)
|
|
|
|
META_setID(_instanceDefinition)
|
|
META_setComment(_instanceDefinition)
|
|
META_setMultitexture(_instanceDefinition)
|
|
META_addChild(_instanceDefinition)
|
|
|
|
protected:
|
|
|
|
virtual ~InstanceDefinition() {}
|
|
virtual void readRecord(RecordInputStream& in, Document& document)
|
|
{
|
|
in.forward(2);
|
|
_number = (int)in.readUInt16();
|
|
|
|
_instanceDefinition = new osg::Group;
|
|
}
|
|
|
|
virtual void dispose(Document& document)
|
|
{
|
|
// Insert transform(s)
|
|
if (_matrix.valid())
|
|
{
|
|
osg::ref_ptr<osg::MatrixTransform> transform = new osg::MatrixTransform(*_matrix);
|
|
transform->setDataVariance(osg::Object::STATIC);
|
|
transform->addChild(_instanceDefinition.get());
|
|
_instanceDefinition = transform.get();
|
|
}
|
|
|
|
// Add to instance definition table.
|
|
document.setInstanceDefinition(_number,_instanceDefinition.get());
|
|
}
|
|
|
|
};
|
|
|
|
REGISTER_FLTRECORD(InstanceDefinition, INSTANCE_DEFINITION_OP)
|
|
|
|
|
|
|
|
/** InstanceReference
|
|
* The InstanceReference is a leaf record.
|
|
*/
|
|
class InstanceReference : public PrimaryRecord
|
|
{
|
|
public:
|
|
|
|
InstanceReference() {}
|
|
|
|
META_Record(InstanceReference)
|
|
|
|
protected:
|
|
|
|
virtual ~InstanceReference() {}
|
|
virtual void readRecord(RecordInputStream& in, Document& document)
|
|
{
|
|
in.forward(2);
|
|
uint16 number = in.readUInt16();
|
|
|
|
// Get definition.
|
|
osg::Node* instance = document.getInstanceDefinition(number);
|
|
|
|
// Add this implementation to parent implementation.
|
|
if (_parent.valid() && instance)
|
|
_parent->addChild(*instance);
|
|
}
|
|
};
|
|
|
|
REGISTER_FLTRECORD(InstanceReference, INSTANCE_REFERENCE_OP)
|
|
|
|
|
|
|
|
/** Extension
|
|
*/
|
|
class Extension : public PrimaryRecord
|
|
{
|
|
osg::ref_ptr<osg::Group> _extension;
|
|
|
|
public:
|
|
|
|
Extension() {}
|
|
|
|
META_Record(Extension)
|
|
|
|
META_setID(_extension)
|
|
META_setComment(_extension)
|
|
META_setMultitexture(_extension)
|
|
META_addChild(_extension)
|
|
META_dispose(_extension)
|
|
|
|
protected:
|
|
|
|
virtual ~Extension() {}
|
|
virtual void readRecord(RecordInputStream& in, Document& /*document*/)
|
|
{
|
|
std::string id = in.readString(8);
|
|
std::string siteId = in.readString(8);
|
|
in.forward(1);
|
|
|
|
_extension = new osg::Group;
|
|
_extension->setName(id);
|
|
|
|
// Add this implementation to parent implementation.
|
|
if (_parent.valid())
|
|
_parent->addChild(*_extension);
|
|
}
|
|
};
|
|
|
|
REGISTER_FLTRECORD(Extension, EXTENSION_OP)
|
|
|
|
|
|
|
|
/** Object
|
|
*/
|
|
class Object : public PrimaryRecord
|
|
{
|
|
static const unsigned int HIDE_IN_DAYLIGHT = 0x80000000u >> 0;
|
|
static const unsigned int HIDE_AT_DUSK = 0x80000000u >> 1;
|
|
static const unsigned int HIDE_AT_NIGHT = 0x80000000u >> 2;
|
|
static const unsigned int NO_ILLUMINATION = 0x80000000u >> 3;
|
|
static const unsigned int FLAT_SHADED = 0x80000000u >> 4;
|
|
static const unsigned int SHADOW_OBJECT = 0x80000000u >> 5;
|
|
|
|
osg::ref_ptr<osg::Group> _object;
|
|
|
|
public:
|
|
|
|
Object() {}
|
|
|
|
META_Record(Object)
|
|
|
|
META_setID(_object)
|
|
META_setComment(_object)
|
|
META_addChild(_object)
|
|
|
|
protected:
|
|
|
|
virtual void readRecord(RecordInputStream& in, Document& document)
|
|
{
|
|
std::string id = in.readString(8);
|
|
|
|
_object = new osg::Group;
|
|
_object->setName(id);
|
|
|
|
if (document.getReadObjectRecordData())
|
|
{
|
|
osgSim::ObjectRecordData* ord = new osgSim::ObjectRecordData;
|
|
ord->_flags = in.readUInt32();
|
|
ord->_relativePriority = in.readInt16();
|
|
ord->_transparency = in.readUInt16();
|
|
ord->_effectID1 = in.readInt16();
|
|
ord->_effectID2 = in.readInt16();
|
|
ord->_significance = in.readInt16();
|
|
|
|
_object->setUserData( ord );
|
|
}
|
|
else
|
|
{
|
|
/*uint32 flags =*/ in.readUInt32();
|
|
}
|
|
|
|
// Postpone add-to-parent until we know a bit more.
|
|
}
|
|
|
|
virtual void dispose(Document& document)
|
|
{
|
|
if (!_parent.valid() || !_object.valid()) return;
|
|
|
|
// Is it safe to remove _object?
|
|
if (!document.getPreserveObject() && isSafeToRemoveObject() && !_matrix.valid())
|
|
{
|
|
// Add children of _object to parent.
|
|
// _object will not be added to graph.
|
|
for (unsigned int i=0; i<_object->getNumChildren(); ++i)
|
|
{
|
|
_parent->addChild(*(_object->getChild(i)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_parent->addChild(*_object);
|
|
}
|
|
|
|
// Insert transform(s)
|
|
if (_matrix.valid())
|
|
{
|
|
insertMatrixTransform(*_object,*_matrix,_numberOfReplications);
|
|
}
|
|
}
|
|
|
|
bool isSafeToRemoveObject() const
|
|
{
|
|
// The following tests need a valid parent.
|
|
if (_parent.valid())
|
|
{
|
|
// LODs adds an empty child group so it is safe to remove this object record.
|
|
if (typeid(*_parent)==typeid(flt::LevelOfDetail))
|
|
return true;
|
|
|
|
if (typeid(*_parent)==typeid(flt::OldLevelOfDetail))
|
|
return true;
|
|
|
|
// If parent is a Group record we have to check for animation.
|
|
Group* parentGroup = dynamic_cast<flt::Group*>(_parent.get());
|
|
if (parentGroup && !parentGroup->hasAnimation())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
};
|
|
|
|
REGISTER_FLTRECORD(Object, OBJECT_OP)
|
|
|
|
|
|
|
|
/** LightSource
|
|
*/
|
|
class LightSource : public PrimaryRecord
|
|
{
|
|
static const unsigned int ENABLED = 0x80000000u >> 0;
|
|
static const unsigned int GLOBAL = 0x80000000u >> 1;
|
|
static const unsigned int EXPORT = 0x80000000u >> 3;
|
|
|
|
osg::ref_ptr<osg::LightSource> _lightSource;
|
|
|
|
public:
|
|
|
|
LightSource() {}
|
|
|
|
META_Record(LightSource)
|
|
|
|
META_setID(_lightSource)
|
|
META_setComment(_lightSource)
|
|
META_dispose(_lightSource)
|
|
|
|
protected:
|
|
|
|
virtual ~LightSource() {}
|
|
virtual void readRecord(RecordInputStream& in, Document& document)
|
|
{
|
|
std::string id = in.readString(8);
|
|
in.forward(4);
|
|
int32 index = in.readInt32();
|
|
in.forward(4);
|
|
uint32 flags = in.readUInt32();
|
|
in.forward(4);
|
|
osg::Vec3d pos = in.readVec3d();
|
|
float32 yaw = in.readFloat32();
|
|
float32 pitch = in.readFloat32();
|
|
|
|
_lightSource = new osg::LightSource;
|
|
_lightSource->setName(id);
|
|
|
|
LightSourcePool* pool = document.getOrCreateLightSourcePool();
|
|
osg::Light* lightFromPool = pool->get(index);
|
|
if (lightFromPool)
|
|
{
|
|
// Make a clone of light in pool.
|
|
osg::Light* light = new osg::Light(*lightFromPool);
|
|
|
|
// TODO: Find a better way to set light number.
|
|
light->setLightNum(1);
|
|
|
|
// Position
|
|
float w = lightFromPool->getPosition().w();
|
|
if (w > 0.0) // positional light?
|
|
light->setPosition(osg::Vec4(pos,w));
|
|
|
|
// Apply yaw and pitch for infinite and spot light.
|
|
if ((w==0.0) || (light->getSpotCutoff()<180.0))
|
|
{
|
|
// TODO: What direction is zero yaw and pitch?
|
|
osg::Quat rotation = ( osg::Quat(osg::inDegrees(double(yaw)),osg::Vec3(0.0,0.0,1.0)) *
|
|
osg::Quat(osg::inDegrees(double(pitch)),osg::Vec3(1.0,0.0,0.0)) );
|
|
light->setDirection(rotation*osg::Vec3(0.0,1.0,0.0));
|
|
}
|
|
|
|
_lightSource->setLight(light);
|
|
_lightSource->setLocalStateSetModes((flags & ENABLED) ? osg::StateAttribute::ON : osg::StateAttribute::OFF);
|
|
|
|
// Global light.
|
|
if (flags & GLOBAL)
|
|
{
|
|
// Apply light source to header node.
|
|
osg::Node* header = document.getHeaderNode();
|
|
if (header)
|
|
_lightSource->setStateSetModes(*(header->getOrCreateStateSet()),osg::StateAttribute::ON);
|
|
}
|
|
}
|
|
|
|
if (_parent.valid())
|
|
_parent->addChild(*_lightSource);
|
|
}
|
|
};
|
|
|
|
REGISTER_FLTRECORD(LightSource, LIGHT_SOURCE_OP)
|
|
|
|
|
|
|
|
} // end namespace
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|