// Copyright (C) 2009 - 2012 Mathias Froehlich - Mathias.Froehlich@web.de // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // 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 GNU // Library General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // #ifdef HAVE_CONFIG_H #include #endif #include "HLASceneObject.hxx" #include #include #include #include #include "HLASceneObjectClass.hxx" #include "HLAViewerFederate.hxx" namespace fgviewer { class HLASceneObject::_ModelDataElement : public simgear::HLAProxyDataElement { public: _ModelDataElement(const SGWeakPtr& sceneObject) : _sceneObject(sceneObject) { } virtual ~_ModelDataElement() { } virtual bool decode(simgear::HLADecodeStream& stream) { if (!HLAProxyDataElement::decode(stream)) return false; // No change? if (!_name.getDataElement()->getDirty()) return true; _name.getDataElement()->setDirty(false); SGSharedPtr sceneObject = _sceneObject.lock(); if (sceneObject.valid()) sceneObject->_setModelFileName(_name.getValue()); return true; } protected: virtual simgear::HLAStringDataElement* _getDataElement() { return _name.getDataElement(); } virtual const simgear::HLAStringDataElement* _getDataElement() const { return _name.getDataElement(); } private: const SGWeakPtr _sceneObject; simgear::HLAStringData _name; }; class HLASceneObject::_Transform : public osg::Transform { public: _Transform(const SGWeakPtr& sceneObject) : _sceneObject(sceneObject) { setCullingActive(false); } virtual ~_Transform() { } virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const { if (!nv) return false; const osg::FrameStamp* frameStamp = nv->getFrameStamp(); if (!frameStamp) return false; SGLocationd location = _getLocation(SGTimeStamp::fromSec(frameStamp->getSimulationTime())); // the position of the view matrix.preMultTranslate(toOsg(location.getPosition())); // the orientation of the view matrix.preMultRotate(toOsg(location.getOrientation())); return true; } virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const { if (!nv) return false; const osg::FrameStamp* frameStamp = nv->getFrameStamp(); if (!frameStamp) return false; SGLocationd location = _getLocation(SGTimeStamp::fromSec(frameStamp->getSimulationTime())); // the position of the view matrix.postMultTranslate(toOsg(-location.getPosition())); // the orientation of the view matrix.postMultRotate(toOsg(inverse(location.getOrientation()))); return true; } virtual osg::BoundingSphere computeBound() const { return osg::BoundingSphere(); } private: SGLocationd _getLocation(const SGTimeStamp& timeStamp) const { // transform from the simulation typical x-forward/y-right/z-down // to the flightgear model system x-back/y-right/z-up // SGQuatd simToModel = SGQuatd::fromEulerDeg(0, 180, 0); SGQuatd simToModel = SGQuatd::fromRealImag(0, SGVec3d(0, 1, 0)); SGSharedPtr sceneObject = _sceneObject.lock(); if (!sceneObject.valid()) return SGLocationd(SGVec3d(0, 0, 0), simToModel); // Get the cartesian location at the given time stamp from the hla object SGLocationd location = sceneObject->getLocation(timeStamp); location.setOrientation(location.getOrientation()*simToModel); return location; } SGWeakPtr _sceneObject; }; HLASceneObject::HLASceneObject(HLASceneObjectClass* objectClass, const SGWeakPtr& federate) : HLAObjectInstance(objectClass), _sceneObject(federate) { _pagedLOD = new osg::PagedLOD; _pagedLOD->setRange(0, 0, 80000); _transform = new _Transform(this); _transform->addChild(_pagedLOD.get()); } HLASceneObject::~HLASceneObject() { _removeFromSceneGraph(); } void HLASceneObject::createAttributeDataElements() { /// FIXME at some point we should not need that anymore HLAObjectInstance::createAttributeDataElements(); assert(dynamic_cast(getObjectClass().get())); HLASceneObjectClass& objectClass = static_cast(*getObjectClass()); simgear::HLACartesianLocation* location = new simgear::HLACartesianLocation; setAttributeDataElement(objectClass.getPositionIndex(), location->getPositionDataElement()); setAttributeDataElement(objectClass.getOrientationIndex(), location->getOrientationDataElement()); setAttributeDataElement(objectClass.getAngularVelocityIndex(), location->getAngularVelocityDataElement()); setAttributeDataElement(objectClass.getLinearVelocityIndex(), location->getLinearVelocityDataElement()); _location = location; setAttributeDataElement(objectClass.getSceneObjectNameIndex(), _sceneObject.getDataElement()); } void HLASceneObject::discoverInstance(const simgear::RTIData& tag) { HLAObjectInstance::discoverInstance(tag); _addToSceneGraph(); } void HLASceneObject::removeInstance(const simgear::RTIData& tag) { _removeFromSceneGraph(); HLAObjectInstance::removeInstance(tag); } void HLASceneObject::registerInstance(simgear::HLAObjectClass* objectClass) { HLAObjectInstance::registerInstance(objectClass); _addToSceneGraph(); } void HLASceneObject::deleteInstance(const simgear::RTIData& tag) { _removeFromSceneGraph(); HLAObjectInstance::deleteInstance(tag); } const HLASceneObject* HLASceneObject::getSceneObject() const { return _sceneObject.getObject(); } HLASceneObject* HLASceneObject::getSceneObject() { return _sceneObject.getObject(); } void HLASceneObject::setSceneObject(HLASceneObject* sceneObject) { _sceneObject.setObject(sceneObject); } SGLocationd HLASceneObject::getLocation(const SGTimeStamp& timeStamp) const { const HLASceneObject* sceneObject = getSceneObject(); if (!sceneObject) return _getRelativeLocation(timeStamp); return sceneObject->getLocation(timeStamp).getAbsoluteLocation(_getRelativeLocation(timeStamp)); } simgear::HLADataElement* HLASceneObject::getModelDataElement() { return new _ModelDataElement(this); } osg::Node* HLASceneObject::getNode() { return _transform.get(); } SGLocationd HLASceneObject::_getRelativeLocation(const SGTimeStamp& timeStamp) const { if (!_location.valid()) return SGLocationd(SGVec3d::zeros(), SGQuatd::unit()); return _location->getLocation(timeStamp); } SGVec3d HLASceneObject::_getRelativeAngularVelocity() const { if (!_location.valid()) return SGVec3d(0, 0, 0); return _location->getAngularBodyVelocity(); } SGVec3d HLASceneObject::_getRelativeLinearVelocity() const { if (!_location.valid()) return SGVec3d(0, 0, 0); return _location->getLinearBodyVelocity(); } void HLASceneObject::_setModelFileName(const std::string& fileName) { if (0 < _pagedLOD->getNumFileNames() && fileName == _pagedLOD->getFileName(0)) return; SGSharedPtr federate = getFederate().lock(); if (federate.valid()) { assert(dynamic_cast(federate.get())); HLAViewerFederate* viewerFederate = static_cast(federate.get()); osg::ref_ptr localOptions; localOptions = static_cast(viewerFederate->getReaderWriterOptions()->clone(osg::CopyOp())); // FIXME: particle systems have some issues. Do not use them currently. localOptions->setPluginStringData("SimGear::PARTICLESYSTEM", "OFF"); _pagedLOD->setDatabaseOptions(localOptions.get()); } // Finally set the file name if (unsigned numChildren = _pagedLOD->getNumChildren()) _pagedLOD->removeChildren(0, numChildren); _pagedLOD->setFileName(0, fileName); } void HLASceneObject::_addToSceneGraph() { SGSharedPtr federate = getFederate().lock(); if (!federate.valid()) return; assert(dynamic_cast(federate.get())); HLAViewerFederate* viewerFederate = static_cast(federate.get()); /// Add ourselves to the dynamic scene graph viewerFederate->addDynamicModel(getNode()); } void HLASceneObject::_removeFromSceneGraph() { /// FIXME O(#SceneObjects), pool them and reuse in create unsigned i = _transform->getNumParents(); while (i--) { osg::Group* parent = _transform->getParent(i); parent->removeChild(_transform.get()); } } } // namespace fgviewer