first commit
This commit is contained in:
30
src/Cockpit/CMakeLists.txt
Normal file
30
src/Cockpit/CMakeLists.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
include(FlightGearComponent)
|
||||
|
||||
set(SOURCES
|
||||
cockpitDisplayManager.cxx
|
||||
panel.cxx
|
||||
panel_io.cxx
|
||||
built_in/FGMagRibbon.cxx
|
||||
agradar.cxx
|
||||
groundradar.cxx
|
||||
od_gauge.cxx
|
||||
render_area_2d.cxx
|
||||
wxradar.cxx
|
||||
NavDisplay.cxx
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
cockpitDisplayManager.hxx
|
||||
panel.hxx
|
||||
panel_io.hxx
|
||||
built_in/FGMagRibbon.hxx
|
||||
agradar.hxx
|
||||
groundradar.hxx
|
||||
od_gauge.hxx
|
||||
render_area_2d.hxx
|
||||
wxradar.hxx
|
||||
NavDisplay.hxx
|
||||
)
|
||||
|
||||
|
||||
flightgear_component(Cockpit "${SOURCES}" "${HEADERS}")
|
||||
1461
src/Cockpit/NavDisplay.cxx
Normal file
1461
src/Cockpit/NavDisplay.cxx
Normal file
File diff suppressed because it is too large
Load Diff
211
src/Cockpit/NavDisplay.hxx
Normal file
211
src/Cockpit/NavDisplay.hxx
Normal file
@@ -0,0 +1,211 @@
|
||||
// Wx Radar background texture
|
||||
//
|
||||
// Written by Harald JOHNSEN, started May 2005.
|
||||
// With major amendments by Vivian MEAZZA May 2007
|
||||
// Ported to OSG by Tim MOORE Jun 2007
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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.
|
||||
|
||||
#ifndef _INST_ND_HXX
|
||||
#define _INST_ND_HXX
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Texture2D>
|
||||
#include <osgText/Text>
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include <Navaids/positioned.hxx>
|
||||
|
||||
class FGODGauge;
|
||||
class FGRouteMgr;
|
||||
class FGNavRecord;
|
||||
|
||||
class SymbolInstance;
|
||||
class SymbolDef;
|
||||
class SymbolRule;
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
class Waypt;
|
||||
}
|
||||
|
||||
typedef std::set<std::string> string_set;
|
||||
typedef std::vector<SymbolRule*> SymbolRuleVector;
|
||||
typedef std::vector<SymbolDef*> SymbolDefVector;
|
||||
|
||||
class NavDisplay : public SGSubsystem
|
||||
{
|
||||
public:
|
||||
|
||||
NavDisplay(SGPropertyNode *node);
|
||||
virtual ~NavDisplay();
|
||||
|
||||
// Subsystem API.
|
||||
void init() override;
|
||||
void update(double dt) override;
|
||||
|
||||
// Subsystem identification.
|
||||
static const char* staticSubsystemClassId() { return "navigation-display"; }
|
||||
|
||||
void invalidatePositionedCache()
|
||||
{
|
||||
_cachedItemsValid = false;
|
||||
}
|
||||
|
||||
double textureSize() const
|
||||
{ return _textureSize; }
|
||||
|
||||
void forceUpdate()
|
||||
{ _forceUpdate = true; }
|
||||
|
||||
bool anyRuleForType(const std::string& type) const;
|
||||
bool isPositionedShown(FGPositioned* pos);
|
||||
|
||||
protected:
|
||||
std::string _name;
|
||||
int _num;
|
||||
double _time;
|
||||
double _updateInterval;
|
||||
bool _forceUpdate;
|
||||
|
||||
SGPropertyNode_ptr _serviceable_node;
|
||||
SGPropertyNode_ptr _Instrument;
|
||||
SGPropertyNode_ptr _radar_mode_control_node;
|
||||
SGPropertyNode_ptr _user_heading_node;
|
||||
SGPropertyNode_ptr _testModeNode;
|
||||
SGPropertyNode_ptr _userLatNode, _userLonNode, _userPositionEnable;
|
||||
|
||||
FGODGauge *_odg;
|
||||
|
||||
// Convenience function for creating a property node with a
|
||||
// default value
|
||||
template<typename DefaultType>
|
||||
SGPropertyNode *getInstrumentNode(const char *name, DefaultType value);
|
||||
|
||||
private:
|
||||
friend class SymbolRule;
|
||||
friend class SymbolDef;
|
||||
|
||||
void addRule(SymbolRule*);
|
||||
|
||||
void addSymbolsToScene();
|
||||
void addSymbolToScene(SymbolInstance* sym);
|
||||
void limitDisplayedSymbols();
|
||||
|
||||
void findItems();
|
||||
void isPositionedShownInner(FGPositioned* pos, SymbolRuleVector& rules);
|
||||
void foundPositionedItem(FGPositioned* pos);
|
||||
void computePositionedPropsAndHeading(FGPositioned* pos, SGPropertyNode* nd, double& heading);
|
||||
void computePositionedState(FGPositioned* pos, string_set& states);
|
||||
void processRoute();
|
||||
void computeWayptPropsAndHeading(flightgear::Waypt* wpt, const SGGeod& pos, SGPropertyNode* nd, double& heading);
|
||||
void processNavRadios();
|
||||
FGNavRecord* processNavRadio(const SGPropertyNode_ptr& radio);
|
||||
void processAI();
|
||||
void computeAIStates(const SGPropertyNode* ai, string_set& states);
|
||||
|
||||
void computeCustomSymbolStates(const SGPropertyNode* sym, string_set& states);
|
||||
void processCustomSymbols();
|
||||
|
||||
void findRules(const std::string& type, const string_set& states, SymbolRuleVector& rules);
|
||||
|
||||
SymbolInstance* addSymbolInstance(const osg::Vec2& proj, double heading, SymbolDef* def, SGPropertyNode* vars);
|
||||
void addLine(osg::Vec2 a, osg::Vec2 b, const osg::Vec4& color);
|
||||
osg::Vec2 projectBearingRange(double bearingDeg, double rangeNm) const;
|
||||
osg::Vec2 projectGeod(const SGGeod& geod) const;
|
||||
bool isProjectedClipped(const osg::Vec2& projected) const;
|
||||
void updateFont();
|
||||
|
||||
void addTestSymbol(const std::string& type, const std::string& states, const SGGeod& pos, double heading, SGPropertyNode* vars);
|
||||
void addTestSymbols();
|
||||
|
||||
std::string _texture_path;
|
||||
unsigned int _textureSize;
|
||||
|
||||
float _scale; // factor to convert nm to display units
|
||||
float _view_heading;
|
||||
|
||||
SGPropertyNode_ptr _Radar_controls;
|
||||
|
||||
|
||||
SGPropertyNode_ptr _font_node;
|
||||
SGPropertyNode_ptr _ai_enabled_node;
|
||||
SGPropertyNode_ptr _navRadio1Node;
|
||||
SGPropertyNode_ptr _navRadio2Node;
|
||||
SGPropertyNode_ptr _xCenterNode, _yCenterNode;
|
||||
SGPropertyNode_ptr _viewHeadingNode;
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> _symbolTexture;
|
||||
osg::ref_ptr<osg::Geode> _radarGeode;
|
||||
osg::ref_ptr<osg::Geode> _textGeode;
|
||||
|
||||
osg::Geometry *_geom;
|
||||
|
||||
osg::DrawArrays* _symbolPrimSet;
|
||||
osg::Vec2Array *_vertices;
|
||||
osg::Vec2Array *_texCoords;
|
||||
osg::Vec4Array* _quadColors;
|
||||
|
||||
osg::Geometry* _lineGeometry;
|
||||
osg::DrawArrays* _linePrimSet;
|
||||
osg::Vec2Array* _lineVertices;
|
||||
osg::Vec4Array* _lineColors;
|
||||
|
||||
|
||||
osg::Matrixf _centerTrans;
|
||||
osg::Matrixf _projectMat;
|
||||
|
||||
osg::ref_ptr<osgText::Font> _font;
|
||||
osg::Vec4 _font_color;
|
||||
float _font_size;
|
||||
float _font_spacing;
|
||||
|
||||
FGRouteMgr* _route;
|
||||
SGGeod _pos;
|
||||
double _rangeNm;
|
||||
SGPropertyNode_ptr _rangeNode;
|
||||
|
||||
SymbolDefVector _definitions;
|
||||
SymbolRuleVector _rules;
|
||||
FGNavRecord* _nav1Station;
|
||||
FGNavRecord* _nav2Station;
|
||||
std::vector<SymbolInstance*> _symbols;
|
||||
std::set<FGPositioned*> _routeSources;
|
||||
|
||||
bool _cachedItemsValid;
|
||||
SGVec3d _cachedPos;
|
||||
FGPositionedList _itemsInRange;
|
||||
SGPropertyNode_ptr _excessDataNode;
|
||||
int _maxSymbols;
|
||||
SGPropertyNode_ptr _customSymbols;
|
||||
|
||||
class CacheListener;
|
||||
std::unique_ptr<CacheListener> _cacheListener;
|
||||
|
||||
class ForceUpdateListener;
|
||||
std::unique_ptr<ForceUpdateListener> _forceUpdateListener;
|
||||
};
|
||||
|
||||
#endif // _INST_ND_HXX
|
||||
9
src/Cockpit/README
Normal file
9
src/Cockpit/README
Normal file
@@ -0,0 +1,9 @@
|
||||
src/Cockpit/ - instrument and display-related code
|
||||
|
||||
This directory contains various subsystems and code modules related to
|
||||
the cockpit, including the HUD and the 2D panel. The code from here
|
||||
is gradually being sorted out into separate code modules -- please do
|
||||
not add anything new here. All new code for gauges and avionics
|
||||
should go in src/Instrumentation/, and all new code aircraft systems
|
||||
(like the electrical or vacuum systems) should go in src/Systems/.
|
||||
Any new 2D or 3D modelling code should go in src/Model/.
|
||||
329
src/Cockpit/agradar.cxx
Normal file
329
src/Cockpit/agradar.cxx
Normal file
@@ -0,0 +1,329 @@
|
||||
// Air Ground Radar
|
||||
//
|
||||
// Written by Vivian MEAZZA, started Feb 2008.
|
||||
//
|
||||
//
|
||||
// Copyright (C) 2008 Vivian Meazza
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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 "config.h"
|
||||
#endif
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
#include "agradar.hxx"
|
||||
|
||||
|
||||
agRadar::agRadar(SGPropertyNode *node) : wxRadarBg(node)
|
||||
{
|
||||
|
||||
_name = node->getStringValue("name", "air-ground-radar");
|
||||
_num = node->getIntValue("number", 0);
|
||||
|
||||
}
|
||||
|
||||
agRadar::~agRadar ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
agRadar::init ()
|
||||
{
|
||||
_user_hdg_deg_node = fgGetNode("/orientation/heading-deg", true);
|
||||
_user_pitch_deg_node = fgGetNode("/orientation/pitch-deg", true);
|
||||
_user_roll_deg_node = fgGetNode("/orientation/roll-deg", true);
|
||||
|
||||
_terrain_warning_node = fgGetNode("/sim/alarms/terrain-warning", true);
|
||||
_terrain_warning_node->setBoolValue(false);
|
||||
|
||||
wxRadarBg::init();
|
||||
|
||||
// those properties are used by a radar instrument of a MFD
|
||||
// input switch = OFF | TST | STBY | ON
|
||||
// input mode = WX | WXA | MAP | TW
|
||||
// output status = STBY | TEST | WX | WXA | MAP | blank
|
||||
// input lightning = true | false
|
||||
// input TRK = +/- n degrees
|
||||
// input TILT = +/- n degree
|
||||
// input autotilt = true | false
|
||||
// input range = n nm (20/40/80)
|
||||
// input display-mode = arc | rose | map | plan
|
||||
|
||||
_Instrument->setFloatValue("trk", 0.0);
|
||||
_Instrument->setFloatValue("tilt",-2.5);
|
||||
_Instrument->setStringValue("status","");
|
||||
_Instrument->setIntValue("mode-control", 5);
|
||||
|
||||
_Instrument->setBoolValue("stabilisation/roll", false);
|
||||
_Instrument->setBoolValue("stabilisation/pitch", false);
|
||||
|
||||
_xOffsetMNode = getInstrumentNode("antenna/x-offset-m", 0.0);
|
||||
_yOffsetMNode = getInstrumentNode("antenna/y-offset-m", 0.0);
|
||||
_zOffsetMNode = getInstrumentNode("antenna/z-offset-m", 0.0);
|
||||
|
||||
_elevLimitDegNode = getInstrumentNode("terrain-warning/elev-limit-deg", 2.0);
|
||||
_elevStepDegNode = getInstrumentNode("terrain-warning/elev-step-deg", 1.0);
|
||||
_azLimitDegNode = getInstrumentNode("terrain-warning/az-limit-deg", 1.0);
|
||||
_azStepDegNode = getInstrumentNode("terrain-warning/az-step-deg", 1.5);
|
||||
_maxRangeMNode = getInstrumentNode("terrain-warning/max-range-m", 4000.0);
|
||||
_minRangeMNode = getInstrumentNode("terrain-warning/min-range-m", 250.0);
|
||||
_tiltNode = getInstrumentNode("terrain-warning/tilt", -2.0);
|
||||
|
||||
_brgDegNode = getInstrumentNode("terrain-warning/hit/brg-deg", 0.0);
|
||||
_rangeMNode = getInstrumentNode("terrain-warning/hit/range-m", 0.0);
|
||||
_elevationMNode = getInstrumentNode("terrain-warning/hit/elevation-m", 0.0);
|
||||
_materialNode = getInstrumentNode("terrain-warning/hit/material", "");
|
||||
_bumpinessNode = getInstrumentNode("terrain-warning/hit/bumpiness", 0.0);
|
||||
|
||||
_rollStabNode = getInstrumentNode("terrain-warning/stabilisation/roll",
|
||||
true);
|
||||
_pitchStabNode = getInstrumentNode("terrain-warning/stabilisation/pitch",
|
||||
false);
|
||||
// cout << "init done" << endl;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
agRadar::update (double delta_time_sec)
|
||||
{
|
||||
if (!_sceneryLoaded->getBoolValue())
|
||||
return;
|
||||
|
||||
if ( !_odg || ! _serviceable_node->getBoolValue() ) {
|
||||
_Instrument->setStringValue("status","");
|
||||
return;
|
||||
}
|
||||
|
||||
_time += delta_time_sec;
|
||||
|
||||
if (_time < _interval)
|
||||
return;
|
||||
|
||||
_time = 0.0;
|
||||
|
||||
update_terrain();
|
||||
// wxRadarBg::update(delta_time_sec);
|
||||
}
|
||||
|
||||
void
|
||||
agRadar::setUserPos()
|
||||
{
|
||||
userpos.setLatitudeDeg(_user_lat_node->getDoubleValue());
|
||||
userpos.setLongitudeDeg(_user_lon_node->getDoubleValue());
|
||||
userpos.setElevationM(_user_alt_node->getDoubleValue() * SG_FEET_TO_METER);
|
||||
}
|
||||
|
||||
SGVec3d
|
||||
agRadar::getCartUserPos() const {
|
||||
SGVec3d cartUserPos = SGVec3d::fromGeod(userpos);
|
||||
return cartUserPos;
|
||||
}
|
||||
|
||||
SGVec3d
|
||||
agRadar::getCartAntennaPos() const {
|
||||
|
||||
float yaw = _user_hdg_deg_node->getDoubleValue();
|
||||
float pitch = _user_pitch_deg_node->getDoubleValue();
|
||||
float roll = _user_roll_deg_node->getDoubleValue();
|
||||
|
||||
double x_offset_m =_xOffsetMNode->getDoubleValue();
|
||||
double y_offset_m =_yOffsetMNode->getDoubleValue();
|
||||
double z_offset_m =_zOffsetMNode->getDoubleValue();
|
||||
|
||||
// convert geodetic positions to geocentered
|
||||
SGVec3d cartuserPos = getCartUserPos();
|
||||
|
||||
// Transform to the right coordinate frame, configuration is done in
|
||||
// the x-forward, y-right, z-up coordinates (feet), computation
|
||||
// in the simulation usual body x-forward, y-right, z-down coordinates
|
||||
// (meters) )
|
||||
SGVec3d _off(x_offset_m, y_offset_m, -z_offset_m);
|
||||
|
||||
// Transform the user position to the horizontal local coordinate system.
|
||||
SGQuatd hlTrans = SGQuatd::fromLonLat(userpos);
|
||||
|
||||
// and postrotate the orientation of the user model wrt the horizontal
|
||||
// local frame
|
||||
hlTrans *= SGQuatd::fromYawPitchRollDeg(yaw,pitch,roll);
|
||||
|
||||
// The offset converted to the usual body fixed coordinate system
|
||||
// rotated to the earth-fixed coordinates axis
|
||||
SGVec3d off = hlTrans.backTransform(_off);
|
||||
|
||||
// Add the position offset of the user model to get the geocentered position
|
||||
SGVec3d offsetPos = cartuserPos + off;
|
||||
|
||||
return offsetPos;
|
||||
}
|
||||
|
||||
void
|
||||
agRadar::setAntennaPos() {
|
||||
SGGeodesy::SGCartToGeod(getCartAntennaPos(), antennapos);
|
||||
}
|
||||
|
||||
void
|
||||
agRadar::setUserVec(double az, double el)
|
||||
{
|
||||
float yaw = _user_hdg_deg_node->getDoubleValue();
|
||||
float pitch = _user_pitch_deg_node->getDoubleValue();
|
||||
float roll = _user_roll_deg_node->getDoubleValue();
|
||||
double tilt = _Instrument->getDoubleValue("tilt");
|
||||
double trk = _Instrument->getDoubleValue("trk");
|
||||
bool roll_stab = _Instrument->getBoolValue("stabilisation/roll");
|
||||
bool pitch_stab = _Instrument->getBoolValue("stabilisation/pitch");
|
||||
|
||||
SGQuatd offset = SGQuatd::fromYawPitchRollDeg(az + trk, el + tilt, 0);
|
||||
|
||||
// Transform the antenna position to the horizontal local coordinate system.
|
||||
SGQuatd hlTrans = SGQuatd::fromLonLat(antennapos);
|
||||
|
||||
// and postrotate the orientation of the radar wrt the horizontal
|
||||
// local frame
|
||||
hlTrans *= SGQuatd::fromYawPitchRollDeg(yaw,
|
||||
pitch_stab ? 0 :pitch,
|
||||
roll_stab ? 0 : roll);
|
||||
hlTrans *= offset;
|
||||
|
||||
// now rotate the rotation vector back into the
|
||||
// earth centered frames coordinates
|
||||
SGVec3d angleaxis(1,0,0);
|
||||
uservec = hlTrans.backTransform(angleaxis);
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
agRadar::getMaterial(){
|
||||
|
||||
const simgear::BVHMaterial* mat = 0;
|
||||
if (globals->get_scenery()->get_elevation_m(hitpos, _elevation_m, &mat)){
|
||||
//_ht_agl_ft = pos.getElevationFt() - _elevation_m * SG_METER_TO_FEET;
|
||||
const SGMaterial* material = dynamic_cast<const SGMaterial*>(mat);
|
||||
if (material) {
|
||||
const std::vector<std::string>& names = material->get_names();
|
||||
|
||||
_solid = material->get_solid();
|
||||
_load_resistance = material->get_load_resistance();
|
||||
_frictionFactor = material->get_friction_factor();
|
||||
_bumpinessFactor = material->get_bumpiness();
|
||||
|
||||
if (!names.empty())
|
||||
_mat_name = names[0];
|
||||
else
|
||||
_mat_name = "";
|
||||
|
||||
}
|
||||
/*cout << "material " << mat_name
|
||||
<< " solid " << _solid
|
||||
<< " load " << _load_resistance
|
||||
<< " frictionFactor " << frictionFactor
|
||||
<< " _bumpinessFactor " << _bumpinessFactor
|
||||
<< endl;*/
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
agRadar::update_terrain()
|
||||
{
|
||||
int mode = _radar_mode_control_node->getIntValue();
|
||||
|
||||
double el_limit = 1;
|
||||
double el_step = 1;
|
||||
double az_limit = 50;
|
||||
double az_step = 10;
|
||||
double max_range = 40000;
|
||||
double min_range = 250;
|
||||
double tilt = -2.5;
|
||||
bool roll_stab = _rollStabNode->getBoolValue();
|
||||
bool pitch_stab = _pitchStabNode->getBoolValue();
|
||||
const char* status = "";
|
||||
bool hdg_mkr = true;
|
||||
|
||||
if (mode == 5){
|
||||
status = "TW";
|
||||
hdg_mkr = false;
|
||||
tilt = _tiltNode->getDoubleValue();
|
||||
el_limit = _elevLimitDegNode->getDoubleValue();
|
||||
el_step = _elevStepDegNode->getDoubleValue();
|
||||
az_limit = _azLimitDegNode->getDoubleValue();
|
||||
az_step = _azStepDegNode->getDoubleValue();
|
||||
max_range = _maxRangeMNode->getDoubleValue();
|
||||
min_range = _minRangeMNode->getDoubleValue();
|
||||
}
|
||||
|
||||
_Instrument->setDoubleValue("tilt", tilt);
|
||||
_Instrument->setBoolValue("stabilisation/roll", roll_stab);
|
||||
_Instrument->setBoolValue("stabilisation/pitch", pitch_stab);
|
||||
_Instrument->setStringValue("status", status);
|
||||
_Instrument->setDoubleValue("limit-deg", az_limit);
|
||||
_Instrument->setBoolValue("heading-marker", hdg_mkr);
|
||||
setUserPos();
|
||||
setAntennaPos();
|
||||
SGVec3d cartantennapos = getCartAntennaPos();
|
||||
|
||||
for(double brg = -az_limit; brg <= az_limit; brg += az_step){
|
||||
for(double elev = el_limit; elev >= - el_limit; elev -= el_step){
|
||||
setUserVec(brg, elev);
|
||||
SGVec3d nearestHit;
|
||||
globals->get_scenery()->get_cart_ground_intersection(cartantennapos, uservec, nearestHit);
|
||||
SGGeodesy::SGCartToGeod(nearestHit, hitpos);
|
||||
|
||||
double course1, course2, distance;
|
||||
|
||||
SGGeodesy::inverse(hitpos, antennapos, course1, course2, distance);
|
||||
|
||||
if (distance >= min_range && distance <= max_range) {
|
||||
_terrain_warning_node->setBoolValue(true);
|
||||
getMaterial();
|
||||
_brgDegNode->setDoubleValue(course2);
|
||||
_rangeMNode->setDoubleValue(distance);
|
||||
_materialNode->setStringValue(_mat_name.c_str());
|
||||
_bumpinessNode->setDoubleValue(_bumpinessFactor);
|
||||
_elevationMNode->setDoubleValue(_elevation_m);
|
||||
} else {
|
||||
_terrain_warning_node->setBoolValue(false);
|
||||
_brgDegNode->setDoubleValue(0);
|
||||
_rangeMNode->setDoubleValue(0);
|
||||
_materialNode->setStringValue("");
|
||||
_bumpinessNode->setDoubleValue(0);
|
||||
_elevationMNode->setDoubleValue(0);
|
||||
}
|
||||
|
||||
//cout << "usr hdg " << _user_hdg_deg_node->getDoubleValue()
|
||||
// << " ant brg " << course2
|
||||
// << " elev " << _Instrument->getDoubleValue("tilt")
|
||||
// << " gnd rng nm " << distance * SG_METER_TO_NM
|
||||
// << " ht " << hitpos.getElevationFt()
|
||||
// << " mat " << _mat_name
|
||||
// << " solid " << _solid
|
||||
// << " bumpiness " << _bumpinessFactor
|
||||
// << endl;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Register the subsystem.
|
||||
#if 0
|
||||
SGSubsystemMgr::Registrant<agRadar> registrantagRadar;
|
||||
#endif
|
||||
98
src/Cockpit/agradar.hxx
Normal file
98
src/Cockpit/agradar.hxx
Normal file
@@ -0,0 +1,98 @@
|
||||
// Air Ground Radar
|
||||
//
|
||||
// Written by Vivian MEAZZA, started Feb 2008.
|
||||
//
|
||||
//
|
||||
// Copyright (C) 2008 Vivain MEAZZA - vivian.meazza@lineone.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _INST_AGRADAR_HXX
|
||||
#define _INST_AGRADAR_HXX
|
||||
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <Scenery/scenery.hxx>
|
||||
#include <simgear/scene/material/mat.hxx>
|
||||
|
||||
#include "wxradar.hxx"
|
||||
|
||||
class agRadar : public wxRadarBg
|
||||
{
|
||||
public:
|
||||
agRadar ( SGPropertyNode *node );
|
||||
agRadar ();
|
||||
virtual ~agRadar ();
|
||||
|
||||
// Subsystem API.
|
||||
void init() override;
|
||||
void update(double dt) override;
|
||||
|
||||
// Subsystem identification.
|
||||
static const char* staticSubsystemClassId() { return "air-ground-radar"; }
|
||||
|
||||
void setUserPos();
|
||||
void setUserVec(double az, double el);
|
||||
void update_terrain();
|
||||
void setAntennaPos();
|
||||
|
||||
bool getMaterial();
|
||||
|
||||
double _load_resistance; // ground load resistanc N/m^2
|
||||
double _frictionFactor; // dimensionless modifier for Coefficient of Friction
|
||||
double _bumpinessFactor; // dimensionless modifier for Bumpiness
|
||||
double _elevation_m; // ground elevation in meters
|
||||
bool _solid; // if true ground is solid for FDMs
|
||||
|
||||
std::string _mat_name; // ground material
|
||||
|
||||
SGVec3d getCartUserPos() const;
|
||||
SGVec3d getCartAntennaPos()const;
|
||||
|
||||
SGVec3d uservec;
|
||||
|
||||
SGPropertyNode_ptr _user_hdg_deg_node;
|
||||
SGPropertyNode_ptr _user_roll_deg_node;
|
||||
SGPropertyNode_ptr _user_pitch_deg_node;
|
||||
SGPropertyNode_ptr _terrain_warning_node;
|
||||
|
||||
SGPropertyNode_ptr _xOffsetMNode;
|
||||
SGPropertyNode_ptr _yOffsetMNode;
|
||||
SGPropertyNode_ptr _zOffsetMNode;
|
||||
|
||||
SGPropertyNode_ptr _elevLimitDegNode;
|
||||
SGPropertyNode_ptr _elevStepDegNode;
|
||||
SGPropertyNode_ptr _azLimitDegNode;
|
||||
SGPropertyNode_ptr _azStepDegNode;
|
||||
SGPropertyNode_ptr _maxRangeMNode;
|
||||
SGPropertyNode_ptr _minRangeMNode;
|
||||
SGPropertyNode_ptr _tiltNode;
|
||||
|
||||
SGPropertyNode_ptr _brgDegNode;
|
||||
SGPropertyNode_ptr _rangeMNode;
|
||||
SGPropertyNode_ptr _elevationMNode;
|
||||
SGPropertyNode_ptr _materialNode;
|
||||
SGPropertyNode_ptr _bumpinessNode;
|
||||
|
||||
SGPropertyNode_ptr _rollStabNode;
|
||||
SGPropertyNode_ptr _pitchStabNode;
|
||||
|
||||
SGGeod userpos;
|
||||
SGGeod hitpos;
|
||||
SGGeod antennapos;
|
||||
};
|
||||
|
||||
#endif // _INST_AGRADAR_HXX
|
||||
86
src/Cockpit/built_in/FGMagRibbon.cxx
Normal file
86
src/Cockpit/built_in/FGMagRibbon.cxx
Normal file
@@ -0,0 +1,86 @@
|
||||
// FGMagRibbon.cxx - Built-in layer for the magnetic compass ribbon layer.
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "FGMagRibbon.hxx"
|
||||
|
||||
|
||||
FGMagRibbon::FGMagRibbon (int w, int h)
|
||||
: FGTexturedLayer(w, h)
|
||||
{
|
||||
FGCroppedTexture texture("Aircraft/Instruments/Textures/compass-ribbon.rgb");
|
||||
setTexture(texture);
|
||||
_magcompass_node =
|
||||
fgGetNode("/instrumentation/magnetic-compass/indicated-heading-deg",
|
||||
true);
|
||||
}
|
||||
|
||||
void
|
||||
FGMagRibbon::draw (osg::State& state)
|
||||
{
|
||||
double heading = _magcompass_node->getDoubleValue();
|
||||
double xoffset, yoffset;
|
||||
|
||||
while (heading >= 360.0) {
|
||||
heading -= 360.0;
|
||||
}
|
||||
while (heading < 0.0) {
|
||||
heading += 360.0;
|
||||
}
|
||||
|
||||
if (heading >= 60.0 && heading <= 180.0) {
|
||||
xoffset = heading / 240.0;
|
||||
yoffset = 0.75;
|
||||
} else if (heading >= 150.0 && heading <= 270.0) {
|
||||
xoffset = (heading - 90.0) / 240.0;
|
||||
yoffset = 0.50;
|
||||
} else if (heading >= 240.0 && heading <= 360.0) {
|
||||
xoffset = (heading - 180.0) / 240.0;
|
||||
yoffset = 0.25;
|
||||
} else {
|
||||
if (heading < 270.0)
|
||||
heading += 360.0;
|
||||
xoffset = (heading - 270.0) / 240.0;
|
||||
yoffset = 0.0;
|
||||
}
|
||||
|
||||
xoffset = 1.0 - xoffset;
|
||||
// Adjust to put the number in the centre
|
||||
xoffset -= 0.25;
|
||||
|
||||
FGCroppedTexture *t = getTexture();
|
||||
t->setCrop(xoffset, yoffset, xoffset + 0.5, yoffset + 0.25);
|
||||
|
||||
static osg::ref_ptr<osg::StateSet> stateSet = new osg::StateSet;
|
||||
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||
|
||||
state.pushStateSet(stateSet.get());
|
||||
state.apply();
|
||||
|
||||
FGTexturedLayer::draw(state);
|
||||
|
||||
state.popStateSet();
|
||||
state.apply();
|
||||
}
|
||||
|
||||
// end of FGMagRibbon.cxx
|
||||
45
src/Cockpit/built_in/FGMagRibbon.hxx
Normal file
45
src/Cockpit/built_in/FGMagRibbon.hxx
Normal file
@@ -0,0 +1,45 @@
|
||||
// FGMagRibbon.hxx - Built-in layer for the magnetic compass ribbon layer.
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef __FG_MAG_RIBBON_HXX
|
||||
#define __FG_MAG_RIBBON_HXX
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include "../panel.hxx"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Built-in layer for the magnetic compass ribbon layer.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class FGMagRibbon : public FGTexturedLayer
|
||||
{
|
||||
public:
|
||||
FGMagRibbon (int w, int h);
|
||||
virtual ~FGMagRibbon () {}
|
||||
|
||||
virtual void draw (osg::State& state);
|
||||
|
||||
private:
|
||||
SGPropertyNode_ptr _magcompass_node;
|
||||
};
|
||||
|
||||
#endif // __FG_MAG_RIBBON_HXX
|
||||
|
||||
// end of FGMagRibbon.hxx
|
||||
2
src/Cockpit/built_in/README
Normal file
2
src/Cockpit/built_in/README
Normal file
@@ -0,0 +1,2 @@
|
||||
This is special directory for built-in
|
||||
layers of various sorts.
|
||||
129
src/Cockpit/cockpitDisplayManager.cxx
Normal file
129
src/Cockpit/cockpitDisplayManager.cxx
Normal file
@@ -0,0 +1,129 @@
|
||||
// cockpitDisplayManager.cxx -- manage cockpit displays, typically
|
||||
// rendered using a sub-camera or render-texture
|
||||
//
|
||||
// Copyright (C) 2012 James Turner zakalawe@mac.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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.
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "cockpitDisplayManager.hxx"
|
||||
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/sg_inlines.h>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
#include <simgear/debug/ErrorReportingCallback.hxx>
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
|
||||
#include "agradar.hxx"
|
||||
#include "NavDisplay.hxx"
|
||||
#include "groundradar.hxx"
|
||||
#include "wxradar.hxx"
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
|
||||
CockpitDisplayManager::CockpitDisplayManager ()
|
||||
{
|
||||
}
|
||||
|
||||
CockpitDisplayManager::~CockpitDisplayManager ()
|
||||
{
|
||||
}
|
||||
|
||||
SGSubsystem::InitStatus CockpitDisplayManager::incrementalInit()
|
||||
{
|
||||
init();
|
||||
return INIT_DONE;
|
||||
}
|
||||
|
||||
void CockpitDisplayManager::init()
|
||||
{
|
||||
SGPropertyNode_ptr config_props = new SGPropertyNode;
|
||||
SGPropertyNode* path_n = fgGetNode("/sim/instrumentation/path");
|
||||
if (!path_n) {
|
||||
return;
|
||||
}
|
||||
|
||||
SGPath config = globals->resolve_aircraft_path(path_n->getStringValue());
|
||||
if (!config.exists()) {
|
||||
simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::AircraftSystems,
|
||||
"CockpitDisplaysManager: Missing instrumentation file", config);
|
||||
return;
|
||||
}
|
||||
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Reading cockpit displays from " << config );
|
||||
|
||||
try {
|
||||
readProperties( config, config_props );
|
||||
if (!build(config_props)) {
|
||||
throw sg_exception(
|
||||
"Detected an internal inconsistency in the instrumentation\n"
|
||||
"system specification file. See earlier errors for details.");
|
||||
}
|
||||
} catch (const sg_exception& e) {
|
||||
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::AircraftSystems,
|
||||
"Failed to load cockpit displays system:" + e.getFormattedMessage(),
|
||||
e.getLocation());
|
||||
}
|
||||
|
||||
SGSubsystemGroup::init();
|
||||
}
|
||||
|
||||
bool CockpitDisplayManager::build (SGPropertyNode* config_props)
|
||||
{
|
||||
for ( int i = 0; i < config_props->nChildren(); ++i ) {
|
||||
SGPropertyNode *node = config_props->getChild(i);
|
||||
std::string name = node->getNameString();
|
||||
|
||||
std::ostringstream subsystemname;
|
||||
subsystemname << "instrument-" << i << '-'
|
||||
<< node->getStringValue("name", name.c_str());
|
||||
int index = node->getIntValue("number", 0);
|
||||
if (index > 0)
|
||||
subsystemname << '['<< index << ']';
|
||||
std::string id = subsystemname.str();
|
||||
|
||||
if ( name == "radar" ) {
|
||||
set_subsystem( id, new wxRadarBg ( node ) );
|
||||
|
||||
} else if ( name == "groundradar" ) {
|
||||
set_subsystem( id, new GroundRadar( node ) );
|
||||
|
||||
} else if ( name == "air-ground-radar" ) {
|
||||
set_subsystem( id, new agRadar( node ) );
|
||||
|
||||
} else if ( name == "navigation-display" ) {
|
||||
set_subsystem( id, new NavDisplay( node ) );
|
||||
|
||||
} else {
|
||||
// probably a regular instrument
|
||||
continue;
|
||||
}
|
||||
// only add to our list if we build a display
|
||||
_displays.push_back(id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Register the subsystem.
|
||||
SGSubsystemMgr::Registrant<CockpitDisplayManager> registrantCockpitDisplayManager(
|
||||
SGSubsystemMgr::DISPLAY);
|
||||
|
||||
} // of namespace flightgear
|
||||
57
src/Cockpit/cockpitDisplayManager.hxx
Normal file
57
src/Cockpit/cockpitDisplayManager.hxx
Normal file
@@ -0,0 +1,57 @@
|
||||
// cockpitDisplayManager.hxx -- manage cockpit displays, typically
|
||||
// rendered using a sub-camera or render-texture
|
||||
//
|
||||
// Copyright (C) 2012 James Turner zakalawe@mac.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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.
|
||||
|
||||
#ifndef COCKPIT_DISPLAY_MGR_HXX
|
||||
#define COCKPIT_DISPLAY_MGR_HXX 1
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <vector>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
class SGPropertyNode;
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
|
||||
/**
|
||||
* Manage aircraft displays.
|
||||
*/
|
||||
class CockpitDisplayManager : public SGSubsystemGroup
|
||||
{
|
||||
public:
|
||||
CockpitDisplayManager ();
|
||||
virtual ~CockpitDisplayManager ();
|
||||
|
||||
// Subsystem API.
|
||||
void init() override;
|
||||
InitStatus incrementalInit() override;
|
||||
|
||||
// Subsystem identification.
|
||||
static const char* staticSubsystemClassId() { return "cockpit-displays"; }
|
||||
|
||||
private:
|
||||
bool build (SGPropertyNode* config_props);
|
||||
|
||||
std::vector<std::string> _displays;
|
||||
};
|
||||
|
||||
} // of namespace lfightgear
|
||||
|
||||
#endif // COCKPIT_DISPLAY_MGR_HXX
|
||||
359
src/Cockpit/groundradar.cxx
Normal file
359
src/Cockpit/groundradar.cxx
Normal file
@@ -0,0 +1,359 @@
|
||||
// groundradar.cxx - Background layer for the ATC radar.
|
||||
//
|
||||
// Copyright (C) 2007 Csaba Halasz.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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 "config.h"
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <osg/Node>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Camera>
|
||||
#include <osg/Texture2D>
|
||||
#include <osgViewer/Viewer>
|
||||
|
||||
#include <osgText/Text>
|
||||
#include <osgDB/Registry>
|
||||
#include <osgDB/ReaderWriter>
|
||||
#include <osgUtil/Tessellator>
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
#include <Viewer/renderer.hxx>
|
||||
#include <Cockpit/panel.hxx>
|
||||
#include <Airports/airport.hxx>
|
||||
#include <Airports/runways.hxx>
|
||||
#include <Airports/pavement.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/math/beziercurve.hxx>
|
||||
|
||||
#include "groundradar.hxx"
|
||||
|
||||
static const char* airport_source_node_name = "airport-id-source";
|
||||
static const char* default_airport_node_name = "/sim/airport/closest-airport-id";
|
||||
static const char* texture_node_name = "texture-name";
|
||||
static const char* default_texture_name = "Aircraft/Instruments/Textures/od_groundradar.rgb";
|
||||
static const char* range_source_node_name = "range-source";
|
||||
static const char* default_range_node_name = "/instrumentation/radar/range";
|
||||
|
||||
struct SingleFrameCallback : public osg::Camera::DrawCallback
|
||||
{
|
||||
virtual void operator () (const osg::Camera& camera) const
|
||||
{
|
||||
const_cast<osg::Camera&>(camera).setNodeMask(0);
|
||||
}
|
||||
};
|
||||
|
||||
GroundRadar::GroundRadar(SGPropertyNode *node)
|
||||
{
|
||||
_airport_node = fgGetNode(node->getStringValue(airport_source_node_name, default_airport_node_name), true);
|
||||
_range_node = fgGetNode(node->getStringValue(range_source_node_name, default_range_node_name), true);
|
||||
createTexture(node->getStringValue(texture_node_name, default_texture_name));
|
||||
updateTexture();
|
||||
_airport_node->addChangeListener(this);
|
||||
_range_node->addChangeListener(this);
|
||||
}
|
||||
|
||||
GroundRadar::~GroundRadar()
|
||||
{
|
||||
_airport_node->removeChangeListener(this);
|
||||
_range_node->removeChangeListener(this);
|
||||
}
|
||||
|
||||
void GroundRadar::update (double /* dt */)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GroundRadar::valueChanged(SGPropertyNode*)
|
||||
{
|
||||
updateTexture();
|
||||
}
|
||||
|
||||
inline static osg::Vec3 fromPolar(double fi, double r)
|
||||
{
|
||||
return osg::Vec3(sin(fi * SGD_DEGREES_TO_RADIANS) * r, cos(fi * SGD_DEGREES_TO_RADIANS) * r, 0);
|
||||
}
|
||||
|
||||
void GroundRadar::createTexture(const std::string& texture_name)
|
||||
{
|
||||
setSize(TextureHalfSize + TextureHalfSize);
|
||||
allocRT();
|
||||
|
||||
_geode = new osg::Geode();
|
||||
osg::StateSet* stateset = _geode->getOrCreateStateSet();
|
||||
stateset->setMode(GL_BLEND, osg::StateAttribute::OFF);
|
||||
|
||||
osg::Vec4Array* taxi_color = new osg::Vec4Array;
|
||||
taxi_color->push_back(osg::Vec4(0.0f, 0.5f, 0.0f, 1.0f));
|
||||
osg::Vec4Array* rwy_color = new osg::Vec4Array;
|
||||
rwy_color->push_back(osg::Vec4(0.0f, 0.5f, 0.5f, 1.0f));
|
||||
|
||||
osg::Geometry *taxi_geom = new osg::Geometry();
|
||||
taxi_geom->setColorArray(taxi_color);
|
||||
taxi_geom->setColorBinding(osg::Geometry::BIND_OVERALL);
|
||||
taxi_geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 0)); // Taxiways
|
||||
_geode->addDrawable(taxi_geom);
|
||||
|
||||
osg::Geometry *pvt_geom = new osg::Geometry();
|
||||
pvt_geom->setColorArray(taxi_color);
|
||||
pvt_geom->setColorBinding(osg::Geometry::BIND_OVERALL);
|
||||
// no primitive set for the moment. It needs tessellation
|
||||
_geode->addDrawable(pvt_geom);
|
||||
|
||||
osg::Geometry *rwy_geom = new osg::Geometry();
|
||||
rwy_geom->setColorArray(rwy_color);
|
||||
rwy_geom->setColorBinding(osg::Geometry::BIND_OVERALL);
|
||||
rwy_geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 0)); // Runways
|
||||
_geode->addDrawable(rwy_geom);
|
||||
|
||||
osg::Camera* camera = getCamera();
|
||||
camera->setPostDrawCallback(new SingleFrameCallback());
|
||||
camera->addChild(_geode.get());
|
||||
camera->setNodeMask(0);
|
||||
camera->setProjectionMatrixAsOrtho2D(0, getTexture()->getTextureWidth(), 0, getTexture()->getTextureHeight());
|
||||
|
||||
// Texture in the 2D panel system
|
||||
FGTextureManager::addTexture(texture_name, getTexture());
|
||||
}
|
||||
|
||||
void GroundRadar::addRunwayVertices(const FGRunwayBase* aRunway, double aTowerLat, double aTowerLon, double aScale, osg::Vec3Array* aVertices)
|
||||
{
|
||||
double az1, az2, dist_m;
|
||||
geo_inverse_wgs_84(aTowerLat, aTowerLon, aRunway->latitude(), aRunway->longitude(), &az1, &az2, &dist_m);
|
||||
|
||||
osg::Vec3 center = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0);
|
||||
osg::Vec3 leftcenter = fromPolar(aRunway->headingDeg(), aRunway->lengthM() * aScale / 2) + center;
|
||||
osg::Vec3 lefttop = fromPolar(aRunway->headingDeg() - 90, aRunway->widthM() * aScale / 2) + leftcenter;
|
||||
osg::Vec3 leftbottom = leftcenter * 2 - lefttop;
|
||||
osg::Vec3 rightbottom = center * 2 - lefttop;
|
||||
osg::Vec3 righttop = center * 2 - leftbottom;
|
||||
|
||||
aVertices->push_back(lefttop);
|
||||
aVertices->push_back(leftbottom);
|
||||
aVertices->push_back(rightbottom);
|
||||
aVertices->push_back(righttop);
|
||||
}
|
||||
|
||||
osg::Geometry *GroundRadar::addPavementGeometry(const FGPavement* aPavement, double aTowerLat, double aTowerLon, double aScale)
|
||||
{
|
||||
|
||||
osg::ref_ptr<osgUtil::Tessellator> tess = new osgUtil::Tessellator;
|
||||
osg::ref_ptr<osg::Geometry> polygon = new osg::Geometry;
|
||||
osg::ref_ptr<osg::Vec3Array> pts = new osg::Vec3Array;
|
||||
|
||||
double az1, az2, dist_m;
|
||||
const FGPavement::NodeList &nodeLst = aPavement->getNodeList();
|
||||
FGPavement::NodeList::const_iterator it = nodeLst.begin(),
|
||||
loopBegin = it;
|
||||
while ( it != nodeLst.end() )
|
||||
{
|
||||
bool close = (*it)->mClose;
|
||||
geo_inverse_wgs_84(aTowerLat, aTowerLon, (*it)->mPos.getLatitudeDeg(), (*it)->mPos.getLongitudeDeg(), &az1, &az2, &dist_m);
|
||||
osg::Vec3 p1 = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0);
|
||||
const FGPavement::BezierNode *bn = dynamic_cast<const FGPavement::BezierNode *>( it->ptr() );
|
||||
if ( bn != 0 )
|
||||
{
|
||||
geo_inverse_wgs_84(aTowerLat, aTowerLon, bn->mControl.getLatitudeDeg(), bn->mControl.getLongitudeDeg(), &az1, &az2, &dist_m);
|
||||
osg::Vec3 p2 = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0),
|
||||
p3;
|
||||
++it;
|
||||
if ( it == nodeLst.end() || close )
|
||||
{
|
||||
geo_inverse_wgs_84(aTowerLat, aTowerLon, (*loopBegin)->mPos.getLatitudeDeg(), (*loopBegin)->mPos.getLongitudeDeg(), &az1, &az2, &dist_m);
|
||||
}
|
||||
else
|
||||
{
|
||||
geo_inverse_wgs_84(aTowerLat, aTowerLon, (*it)->mPos.getLatitudeDeg(), (*it)->mPos.getLongitudeDeg(), &az1, &az2, &dist_m);
|
||||
}
|
||||
p3 = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0);
|
||||
simgear::BezierCurve<osg::Vec3> bCurv( p1, p2, p3 );
|
||||
simgear::BezierCurve<osg::Vec3>::PointList &ptList = bCurv.pointList();
|
||||
for ( simgear::BezierCurve<osg::Vec3>::PointList::iterator ii = ptList.begin(); ii != ptList.end(); ++ii )
|
||||
{
|
||||
pts->push_back( *ii );
|
||||
}
|
||||
pts->pop_back(); // Last point belongs to next segment
|
||||
}
|
||||
else
|
||||
{
|
||||
pts->push_back( p1 );
|
||||
++it;
|
||||
}
|
||||
|
||||
if ( close ) // One loop for the moment
|
||||
break;
|
||||
}
|
||||
geo_inverse_wgs_84(aTowerLat, aTowerLon, (*loopBegin)->mPos.getLatitudeDeg(), (*loopBegin)->mPos.getLongitudeDeg(), &az1, &az2, &dist_m);
|
||||
osg::Vec3 p1 = fromPolar(az1, dist_m * aScale) + osg::Vec3(TextureHalfSize, TextureHalfSize, 0);
|
||||
pts->push_back( p1 );
|
||||
polygon->setVertexArray( pts.get() );
|
||||
|
||||
polygon->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::POLYGON, 0, pts->size() ) );
|
||||
|
||||
tess->setTessellationType( osgUtil::Tessellator::TESS_TYPE_GEOMETRY );
|
||||
tess->setBoundaryOnly( false );
|
||||
tess->setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD );
|
||||
tess->retessellatePolygons( *polygon );
|
||||
return polygon.release();
|
||||
}
|
||||
|
||||
void GroundRadar::updateTexture()
|
||||
{
|
||||
osg::ref_ptr<osg::Vec3Array> rwy_vertices = new osg::Vec3Array;
|
||||
osg::ref_ptr<osg::Vec3Array> taxi_vertices = new osg::Vec3Array;
|
||||
osg::ref_ptr<osg::Vec3Array> pvt_vertices = new osg::Vec3Array;
|
||||
|
||||
const std::string airport_name = _airport_node->getStringValue();
|
||||
|
||||
const FGAirport* airport = fgFindAirportID(airport_name);
|
||||
if (airport == 0)
|
||||
return;
|
||||
|
||||
const SGGeod& tower_location = airport->getTowerLocation();
|
||||
const double tower_lat = tower_location.getLatitudeDeg();
|
||||
const double tower_lon = tower_location.getLongitudeDeg();
|
||||
double scale = SG_METER_TO_NM * 200 / _range_node->getDoubleValue();
|
||||
|
||||
const FGAirport* apt = fgFindAirportID(airport_name);
|
||||
assert(apt);
|
||||
|
||||
for (unsigned int i=0; i<apt->numTaxiways(); ++i)
|
||||
{
|
||||
FGTaxiway* txwy(apt->getTaxiwayByIndex(i));
|
||||
addRunwayVertices(txwy, tower_lat, tower_lon, scale, taxi_vertices.get());
|
||||
}
|
||||
osg::Geometry *taxi_geom = dynamic_cast<osg::Geometry *>(_geode->getDrawable(0));
|
||||
taxi_geom->setVertexArray(taxi_vertices.get());
|
||||
osg::DrawArrays* taxi = dynamic_cast<osg::DrawArrays*>(taxi_geom->getPrimitiveSet(0));
|
||||
taxi->setCount(taxi_vertices->size());
|
||||
|
||||
osg::Geometry *pvt_geom = dynamic_cast<osg::Geometry *>(_geode->getDrawable(1));
|
||||
osg::Geometry::PrimitiveSetList &pvt_prim_list = pvt_geom->getPrimitiveSetList();
|
||||
pvt_prim_list.clear();
|
||||
|
||||
auto pavementlist = airport->getPavements();
|
||||
for (auto pvtiter = pavementlist.begin(); pvtiter != pavementlist.end(); ++pvtiter)
|
||||
{
|
||||
osg::ref_ptr<osg::Geometry> geom = addPavementGeometry(*pvtiter, tower_lat, tower_lon, scale);
|
||||
osg::Geometry::PrimitiveSetList &prim_list = geom->getPrimitiveSetList();
|
||||
osg::Vec3Array *vertices = dynamic_cast<osg::Vec3Array *>(geom->getVertexArray());
|
||||
size_t before = pvt_vertices->size(),
|
||||
count = vertices->size();
|
||||
for (size_t i = 0; i < count; ++i )
|
||||
{
|
||||
pvt_vertices->push_back( (*vertices)[i] );
|
||||
}
|
||||
for (osg::Geometry::PrimitiveSetList::iterator ii = prim_list.begin(); ii != prim_list.end(); ++ii )
|
||||
{
|
||||
osg::DrawArrays *da;
|
||||
osg::DrawElementsUByte *de1;
|
||||
osg::DrawElementsUShort *de2;
|
||||
osg::DrawElementsUInt *de3;
|
||||
if ((da = dynamic_cast<osg::DrawArrays *>(ii->get())) != 0)
|
||||
{
|
||||
osg::DrawArrays *ps = new osg::DrawArrays(*da);
|
||||
ps->setFirst(da->getFirst() + before);
|
||||
pvt_prim_list.push_back(ps);
|
||||
}
|
||||
else if ((de1 = dynamic_cast<osg::DrawElementsUByte *>(ii->get())) != 0)
|
||||
{
|
||||
if (before + count <= 255)
|
||||
{
|
||||
osg::DrawElementsUByte *ps = new osg::DrawElementsUByte(*de1);
|
||||
for (size_t j = 0; j < ps->size(); ++j)
|
||||
{
|
||||
(*ps)[j] += before;
|
||||
}
|
||||
pvt_prim_list.push_back(ps);
|
||||
}
|
||||
else if (before + count <= 65535)
|
||||
{
|
||||
osg::DrawElementsUShort *ps = new osg::DrawElementsUShort(de1->getMode(), de1->begin(), de1->end());
|
||||
for (size_t j = 0; j < ps->size(); ++j)
|
||||
{
|
||||
(*ps)[j] += before;
|
||||
}
|
||||
pvt_prim_list.push_back(ps);
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::DrawElementsUInt *ps = new osg::DrawElementsUInt(de1->getMode(), de1->begin(), de1->end());
|
||||
for (size_t j = 0; j < ps->size(); ++j)
|
||||
{
|
||||
(*ps)[j] += before;
|
||||
}
|
||||
pvt_prim_list.push_back(ps);
|
||||
}
|
||||
}
|
||||
else if ((de2 = dynamic_cast<osg::DrawElementsUShort *>(ii->get())) != 0)
|
||||
{
|
||||
if (before + count <= 65535)
|
||||
{
|
||||
osg::DrawElementsUShort *ps = new osg::DrawElementsUShort(*de2);
|
||||
for (size_t j = 0; j < ps->size(); ++j)
|
||||
{
|
||||
(*ps)[j] += before;
|
||||
}
|
||||
pvt_prim_list.push_back(ps);
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::DrawElementsUInt *ps = new osg::DrawElementsUInt(de2->getMode(), de2->begin(), de2->end());
|
||||
for (size_t j = 0; j < ps->size(); ++j)
|
||||
{
|
||||
(*ps)[j] += before;
|
||||
}
|
||||
pvt_prim_list.push_back(ps);
|
||||
}
|
||||
}
|
||||
else if ((de3 = dynamic_cast<osg::DrawElementsUInt *>(ii->get())) != 0)
|
||||
{
|
||||
osg::DrawElementsUInt *ps = new osg::DrawElementsUInt(*de3);
|
||||
for (size_t j = 0; j < ps->size(); ++j)
|
||||
{
|
||||
(*ps)[j] += before;
|
||||
}
|
||||
pvt_prim_list.push_back(ps);
|
||||
}
|
||||
}
|
||||
}
|
||||
pvt_geom->setVertexArray(pvt_vertices.get());
|
||||
|
||||
FGRunwayList rwys(apt->getRunwaysWithoutReciprocals());
|
||||
for (unsigned int i=0; i<rwys.size(); ++i)
|
||||
{
|
||||
addRunwayVertices(rwys[i], tower_lat, tower_lon, scale, rwy_vertices.get());
|
||||
}
|
||||
osg::Geometry *rwy_geom = dynamic_cast<osg::Geometry *>(_geode->getDrawable(2));
|
||||
rwy_geom->setVertexArray(rwy_vertices.get());
|
||||
osg::DrawArrays* rwy = dynamic_cast<osg::DrawArrays*>(rwy_geom->getPrimitiveSet(0));
|
||||
rwy->setCount(rwy_vertices->size());
|
||||
|
||||
getCamera()->setNodeMask(0xffffffff);
|
||||
}
|
||||
|
||||
|
||||
// Register the subsystem.
|
||||
#if 0
|
||||
SGSubsystemMgr::Registrant<GroundRadar> registrantGroundRadar;
|
||||
#endif
|
||||
|
||||
// end of GroundRadar.cxx
|
||||
65
src/Cockpit/groundradar.hxx
Normal file
65
src/Cockpit/groundradar.hxx
Normal file
@@ -0,0 +1,65 @@
|
||||
// groundradar.hxx - Background layer for the ATC radar.
|
||||
//
|
||||
// Copyright (C) 2007 Csaba Halasz.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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.
|
||||
|
||||
|
||||
#ifndef __INST_GROUNDRADAR_HXX
|
||||
#define __INST_GROUNDRADAR_HXX
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Geometry>
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
#include "od_gauge.hxx"
|
||||
|
||||
// forward decls
|
||||
class FGRunwayBase;
|
||||
class FGPavement;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Built-in layer for the atc radar.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class GroundRadar : public SGSubsystem,
|
||||
public SGPropertyChangeListener,
|
||||
private FGODGauge
|
||||
{
|
||||
public:
|
||||
// Subsystem identification.
|
||||
static const char* staticSubsystemClassId() { return "groundradar"; }
|
||||
|
||||
static const int TextureHalfSize = 256;
|
||||
GroundRadar(SGPropertyNode* node);
|
||||
virtual ~GroundRadar();
|
||||
void updateTexture();
|
||||
virtual void valueChanged(SGPropertyNode*);
|
||||
virtual void update (double dt);
|
||||
|
||||
protected:
|
||||
void createTexture(const std::string& texture_name);
|
||||
|
||||
void addRunwayVertices(const FGRunwayBase* aRunway, double aTowerLat, double aTowerLon, double aScale, osg::Vec3Array* aVertices);
|
||||
osg::Geometry *addPavementGeometry(const FGPavement* aPavement, double aTowerLat, double aTowerLon, double aScale);
|
||||
|
||||
osg::ref_ptr<osg::Geode> _geode;
|
||||
SGPropertyNode_ptr _airport_node;
|
||||
SGPropertyNode_ptr _range_node;
|
||||
};
|
||||
|
||||
#endif // __INST_GROUNDRADAR_HXX
|
||||
333
src/Cockpit/od_gauge.cxx
Normal file
333
src/Cockpit/od_gauge.cxx
Normal file
@@ -0,0 +1,333 @@
|
||||
// Owner Drawn Gauge helper class
|
||||
//
|
||||
// Written by Harald JOHNSEN, started May 2005.
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN
|
||||
//
|
||||
// Ported to OSG by Tim Moore - Jun 2007
|
||||
//
|
||||
// Heavily modified to be usable for the 2d Canvas by Thomas Geymayer - April 2012
|
||||
// Supports now multisampling/mipmapping, usage of the stencil buffer and placing
|
||||
// the texture in the scene by certain filter criteria
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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 "config.h"
|
||||
#endif
|
||||
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/AlphaFunc>
|
||||
#include <osg/BlendFunc>
|
||||
#include <osg/Camera>
|
||||
#include <osg/Geode>
|
||||
#include <osg/NodeVisitor>
|
||||
#include <osg/Matrix>
|
||||
#include <osg/PolygonMode>
|
||||
#include <osg/ShadeModel>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/FrameBufferObject> // for GL_DEPTH_STENCIL_EXT on Windows
|
||||
|
||||
#include <osgDB/FileNameUtils>
|
||||
|
||||
#include <simgear/canvas/CanvasObjectPlacement.hxx>
|
||||
#include <simgear/scene/material/EffectGeode.hxx>
|
||||
#include <simgear/scene/util/RenderConstants.hxx>
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Scenery/scenery.hxx>
|
||||
#include "od_gauge.hxx"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FGODGauge::FGODGauge()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FGODGauge::~FGODGauge()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to remember the located groups that require modification
|
||||
*/
|
||||
typedef struct {
|
||||
osg::ref_ptr<osg::Group> parent;
|
||||
osg::ref_ptr<osg::Geode> node;
|
||||
unsigned int unit;
|
||||
} GroupListItem;
|
||||
|
||||
/**
|
||||
* Replace a texture in the airplane model with the gauge texture.
|
||||
*/
|
||||
class ReplaceStaticTextureVisitor:
|
||||
|
||||
public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
|
||||
typedef osg::ref_ptr<osg::Group> GroupPtr;
|
||||
typedef osg::ref_ptr<osg::Material> MaterialPtr;
|
||||
|
||||
ReplaceStaticTextureVisitor( const char* name,
|
||||
osg::Texture2D* new_texture ):
|
||||
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||
_tex_name( osgDB::getSimpleFileName(name) ),
|
||||
_new_texture(new_texture),
|
||||
_cull_callback(0)
|
||||
{}
|
||||
|
||||
ReplaceStaticTextureVisitor( SGPropertyNode* placement,
|
||||
osg::Texture2D* new_texture,
|
||||
osg::NodeCallback* cull_callback = 0,
|
||||
const simgear::canvas::CanvasWeakPtr& canvas =
|
||||
simgear::canvas::CanvasWeakPtr() ):
|
||||
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||
_tex_name( osgDB::getSimpleFileName(
|
||||
placement->getStringValue("texture"))
|
||||
),
|
||||
_node_name( placement->getStringValue("node") ),
|
||||
_parent_name( placement->getStringValue("parent") ),
|
||||
_node(placement),
|
||||
_new_texture(new_texture),
|
||||
_cull_callback(cull_callback),
|
||||
_canvas(canvas)
|
||||
{
|
||||
if( _tex_name.empty()
|
||||
&& _node_name.empty()
|
||||
&& _parent_name.empty() )
|
||||
SG_LOG
|
||||
(
|
||||
SG_GL,
|
||||
SG_WARN,
|
||||
"No filter criterion for replacing texture. "
|
||||
" Every texture will be replaced!"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of groups which have been inserted into the scene graph to
|
||||
* replace the given texture
|
||||
*/
|
||||
simgear::canvas::Placements& getPlacements()
|
||||
{
|
||||
return _placements;
|
||||
}
|
||||
|
||||
virtual void apply(osg::Geode& node)
|
||||
{
|
||||
simgear::EffectGeode* effectGeode = dynamic_cast<simgear::EffectGeode*>(&node);
|
||||
if( !effectGeode )
|
||||
return;
|
||||
simgear::Effect* eff = effectGeode->getEffect();
|
||||
if (!eff)
|
||||
return;
|
||||
osg::StateSet* ss = eff->getDefaultStateSet();
|
||||
if( !ss )
|
||||
return;
|
||||
|
||||
osg::Group *parent = node.getParent(0);
|
||||
if( !_node_name.empty() && getNodeName(*parent) != _node_name )
|
||||
return;
|
||||
|
||||
if( !_parent_name.empty() )
|
||||
{
|
||||
// Traverse nodes upwards starting at the parent node (skip current
|
||||
// node)
|
||||
const osg::NodePath& np = getNodePath();
|
||||
bool found = false;
|
||||
for( int i = static_cast<int>(np.size()) - 2; i >= 0; --i )
|
||||
{
|
||||
const osg::Node* path_segment = np[i];
|
||||
const osg::Node* path_parent = path_segment->getParent(0);
|
||||
|
||||
// A node without a name is always the parent of the root node of
|
||||
// the model just containing the file name
|
||||
if( path_parent && path_parent->getName().empty() )
|
||||
return;
|
||||
|
||||
if( path_segment->getName() == _parent_name )
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !found )
|
||||
return;
|
||||
}
|
||||
|
||||
for( unsigned int unit = 0; unit < ss->getNumTextureAttributeLists(); ++unit )
|
||||
{
|
||||
osg::Texture2D* tex = dynamic_cast<osg::Texture2D*>
|
||||
(
|
||||
ss->getTextureAttribute(unit, osg::StateAttribute::TEXTURE)
|
||||
);
|
||||
|
||||
if( !tex || !tex->getImage() || tex == _new_texture )
|
||||
continue;
|
||||
|
||||
if( !_tex_name.empty() )
|
||||
{
|
||||
std::string tex_name = tex->getImage()->getFileName();
|
||||
std::string tex_name_simple = osgDB::getSimpleFileName(tex_name);
|
||||
if( !osgDB::equalCaseInsensitive(_tex_name, tex_name_simple) )
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* remember this group for modification once the scenegraph has been traversed
|
||||
*/
|
||||
groups_to_modify.push_back({ parent, &node, unit });
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* this section of code used to be in the apply method above, however to work this requires modification of the scenegraph nodes
|
||||
* that are currently iterating, so instead the apply method will locate the groups to be modified and when finished then the
|
||||
* nodes can actually be modified safely. Initially found thanks to the debug RTL in MSVC2015 throwing an exception.
|
||||
* should be called immediately after the visitor to ensure that the groups are still valid and that nothing else has modified these groups.
|
||||
*/
|
||||
void modify_groups()
|
||||
{
|
||||
for (auto g : groups_to_modify) {
|
||||
// insert a new group between the geode an it's parent which overrides
|
||||
// the texture
|
||||
GroupPtr group = new osg::Group;
|
||||
group->setName("canvas texture group");
|
||||
group->addChild(g.node);
|
||||
g.parent->removeChild(g.node);
|
||||
g.parent->addChild(group);
|
||||
|
||||
if (_cull_callback)
|
||||
group->setCullCallback(_cull_callback);
|
||||
|
||||
osg::StateSet* stateSet = group->getOrCreateStateSet();
|
||||
stateSet->setTextureAttribute(g.unit, _new_texture,
|
||||
osg::StateAttribute::OVERRIDE);
|
||||
stateSet->setTextureMode(g.unit, GL_TEXTURE_2D,
|
||||
osg::StateAttribute::ON);
|
||||
|
||||
_placements.push_back(simgear::canvas::PlacementPtr(
|
||||
new simgear::canvas::ObjectPlacement(_node, group, _canvas)
|
||||
));
|
||||
|
||||
SG_LOG
|
||||
(
|
||||
SG_GL,
|
||||
SG_INFO,
|
||||
"Replaced texture '" << _tex_name << "'"
|
||||
<< " for object '" << g.parent->getName() << "'"
|
||||
<< (!_parent_name.empty() ? " with parent '" + _parent_name + "'"
|
||||
: "")
|
||||
);
|
||||
}
|
||||
groups_to_modify.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
std::string _tex_name, ///<! Name of texture to be replaced
|
||||
_node_name, ///<! Only replace if node name matches
|
||||
_parent_name; ///<! Only replace if any parent node matches
|
||||
/// given name (all the tree upwards)
|
||||
|
||||
SGPropertyNode_ptr _node;
|
||||
osg::Texture2D *_new_texture;
|
||||
osg::NodeCallback *_cull_callback;
|
||||
typedef std::vector<GroupListItem> GroupList;
|
||||
GroupList groups_to_modify;
|
||||
simgear::canvas::CanvasWeakPtr _canvas;
|
||||
simgear::canvas::Placements _placements;
|
||||
|
||||
const std::string& getNodeName(const osg::Node& node) const
|
||||
{
|
||||
if( !node.getName().empty() )
|
||||
return node.getName();
|
||||
|
||||
// Special handling for pick animation which clears the name of the object
|
||||
// and instead sets the name of a parent group with one or two groups
|
||||
// attached (one for normal rendering and one for the picking highlight).
|
||||
osg::Group const* parent = node.getParent(0);
|
||||
if( parent->getName() == "pick render group" )
|
||||
return parent->getParent(0)->getName();
|
||||
|
||||
return node.getName();
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
simgear::canvas::Placements
|
||||
FGODGauge::set_texture( osg::Node* branch,
|
||||
const char * name,
|
||||
osg::Texture2D* new_texture )
|
||||
{
|
||||
ReplaceStaticTextureVisitor visitor(name, new_texture);
|
||||
branch->accept(visitor);
|
||||
visitor.modify_groups();
|
||||
return visitor.getPlacements();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
simgear::canvas::Placements
|
||||
FGODGauge::set_aircraft_texture( const char* name,
|
||||
osg::Texture2D* new_texture )
|
||||
{
|
||||
return set_texture
|
||||
(
|
||||
globals->get_scenery()->get_aircraft_branch(),
|
||||
name,
|
||||
new_texture
|
||||
);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
simgear::canvas::Placements
|
||||
FGODGauge::set_texture( osg::Node* branch,
|
||||
SGPropertyNode* placement,
|
||||
osg::Texture2D* new_texture,
|
||||
osg::NodeCallback* cull_callback,
|
||||
const simgear::canvas::CanvasWeakPtr& canvas )
|
||||
{
|
||||
ReplaceStaticTextureVisitor visitor( placement,
|
||||
new_texture,
|
||||
cull_callback,
|
||||
canvas );
|
||||
branch->accept(visitor);
|
||||
visitor.modify_groups();
|
||||
return visitor.getPlacements();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
simgear::canvas::Placements
|
||||
FGODGauge::set_aircraft_texture( SGPropertyNode* placement,
|
||||
osg::Texture2D* new_texture,
|
||||
osg::NodeCallback* cull_callback,
|
||||
const simgear::canvas::CanvasWeakPtr& canvas )
|
||||
{
|
||||
return set_texture
|
||||
(
|
||||
globals->get_scenery()->get_aircraft_branch(),
|
||||
placement,
|
||||
new_texture,
|
||||
cull_callback,
|
||||
canvas
|
||||
);
|
||||
}
|
||||
110
src/Cockpit/od_gauge.hxx
Normal file
110
src/Cockpit/od_gauge.hxx
Normal file
@@ -0,0 +1,110 @@
|
||||
// Owner Drawn Gauge helper class
|
||||
//
|
||||
// Moved to SimGear by Thomas Geymayer - October 2012
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _OD_GAUGE_HXX
|
||||
#define _OD_GAUGE_HXX
|
||||
|
||||
#include <simgear/canvas/ODGauge.hxx>
|
||||
#include <simgear/canvas/CanvasPlacement.hxx>
|
||||
|
||||
class SGPropertyNode;
|
||||
|
||||
/**
|
||||
* Owner Drawn Gauge helper class
|
||||
*/
|
||||
class FGODGauge:
|
||||
public simgear::canvas::ODGauge
|
||||
{
|
||||
public:
|
||||
FGODGauge();
|
||||
virtual ~FGODGauge();
|
||||
|
||||
/**
|
||||
* Replace an opengl texture name inside a given branch of the scene graph.
|
||||
* This is to replace a static texture by a dynamic one
|
||||
*
|
||||
* @param branch Scene graph branch to use for search
|
||||
* @param name texture filename
|
||||
* @param new_texture dynamic texture to replace the old one
|
||||
* @return A list of groups which override the given texture
|
||||
*/
|
||||
static
|
||||
simgear::canvas::Placements set_texture( osg::Node* branch,
|
||||
const char * name,
|
||||
osg::Texture2D* new_texture );
|
||||
|
||||
/**
|
||||
* Replace an opengl texture name inside the aircraft scene graph.
|
||||
* This is to replace a static texture by a dynamic one
|
||||
*
|
||||
* @param branch Scene graph branch to search for matching
|
||||
* @param name texture filename
|
||||
* @param new_texture dynamic texture to replace the old one
|
||||
* @return A list of groups which override the given texture
|
||||
*/
|
||||
static
|
||||
simgear::canvas::Placements
|
||||
set_aircraft_texture( const char * name,
|
||||
osg::Texture2D* new_texture );
|
||||
|
||||
/**
|
||||
* Replace an opengl texture name inside a given branch of the scene graph.
|
||||
* This is to replace a static texture by a dynamic one. The replacement
|
||||
* is base on certain filtering criteria which have to be stored in string
|
||||
* value childs of the placement node. Recognized nodes are:
|
||||
* - texture Match the name of the texture
|
||||
* - node Match the name of the object
|
||||
* - parent Match any of the object parents names (all the tree upwards)
|
||||
*
|
||||
* @param placement the node containing the replacement criteria
|
||||
* @param new_texture dynamic texture to replace the old one
|
||||
* @param an optional cull callback which will be installed on any matching
|
||||
* object
|
||||
* @return A list of groups which override the given texture
|
||||
*/
|
||||
static
|
||||
simgear::canvas::Placements
|
||||
set_texture( osg::Node* branch,
|
||||
SGPropertyNode* placement,
|
||||
osg::Texture2D* new_texture,
|
||||
osg::NodeCallback* cull_callback = 0,
|
||||
const simgear::canvas::CanvasWeakPtr& canvas =
|
||||
simgear::canvas::CanvasWeakPtr() );
|
||||
|
||||
/**
|
||||
* Replace an opengl texture name inside the aircraft scene graph.
|
||||
*
|
||||
* @param placement the node containing the replacement criteria
|
||||
* @param new_texture dynamic texture to replace the old one
|
||||
* @param an optional cull callback which will be installed on any matching
|
||||
* object
|
||||
* @return A list of groups which override the given texture
|
||||
*/
|
||||
static
|
||||
simgear::canvas::Placements
|
||||
set_aircraft_texture( SGPropertyNode* placement,
|
||||
osg::Texture2D* new_texture,
|
||||
osg::NodeCallback* cull_callback = 0,
|
||||
const simgear::canvas::CanvasWeakPtr& canvas =
|
||||
simgear::canvas::CanvasWeakPtr() );
|
||||
|
||||
};
|
||||
|
||||
#endif // _OD_GAUGE_HXX
|
||||
1249
src/Cockpit/panel.cxx
Normal file
1249
src/Cockpit/panel.cxx
Normal file
File diff suppressed because it is too large
Load Diff
578
src/Cockpit/panel.hxx
Normal file
578
src/Cockpit/panel.hxx
Normal file
@@ -0,0 +1,578 @@
|
||||
// panel.hxx - generic support classes for a 2D panel.
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef __PANEL_HXX
|
||||
#define __PANEL_HXX
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/Texture2D>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/props/propertyObject.hxx>
|
||||
|
||||
#include <simgear/structure/SGBinding.hxx>
|
||||
#include <simgear/math/interpolater.hxx>
|
||||
#include <simgear/timing/timestamp.hxx>
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
class FGPanelInstrument;
|
||||
class fntFont;
|
||||
class DCLGPS;
|
||||
class IntRect;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Texture management.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Texture manager (should migrate out into FGFS).
|
||||
*
|
||||
* This class ensures that no texture is loaded more than once.
|
||||
*/
|
||||
class FGTextureManager
|
||||
{
|
||||
public:
|
||||
static osg::Texture2D* createTexture(const std::string &relativePath,
|
||||
bool staticTexture = true);
|
||||
static void addTexture(const std::string &relativePath, osg::Texture2D* texture);
|
||||
private:
|
||||
static std::map<std::string,osg::ref_ptr<osg::Texture2D> > _textureMap;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cropped texture (should migrate out into FGFS).
|
||||
*
|
||||
* This structure wraps an SSG texture with cropping information.
|
||||
*/
|
||||
class FGCroppedTexture
|
||||
{
|
||||
public:
|
||||
|
||||
FGCroppedTexture ();
|
||||
FGCroppedTexture (const std::string &path,
|
||||
float _minX = 0.0, float _minY = 0.0,
|
||||
float _maxX = 1.0, float _maxY = 1.0);
|
||||
virtual ~FGCroppedTexture ();
|
||||
|
||||
virtual void setPath (const std::string &path) { _path = path; }
|
||||
|
||||
virtual const std::string &getPath () const { return _path; }
|
||||
|
||||
virtual osg::StateSet* getTexture ();
|
||||
|
||||
virtual void setCrop (float minX, float minY, float maxX, float maxY) {
|
||||
_minX = minX; _minY = minY; _maxX = maxX; _maxY = maxY;
|
||||
}
|
||||
|
||||
virtual float getMinX () const { return _minX; }
|
||||
virtual float getMinY () const { return _minY; }
|
||||
virtual float getMaxX () const { return _maxX; }
|
||||
virtual float getMaxY () const { return _maxY; }
|
||||
|
||||
|
||||
private:
|
||||
std::string _path;
|
||||
osg::ref_ptr<osg::StateSet> _texture;
|
||||
float _minX, _minY, _maxX, _maxY;
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Top-level panel.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Instrument panel class.
|
||||
*
|
||||
* The panel is a container that has a background texture and holds
|
||||
* zero or more instruments. The panel will order the instruments to
|
||||
* redraw themselves when necessary, and will pass mouse clicks on to
|
||||
* the appropriate instruments for processing.
|
||||
*/
|
||||
class FGPanel : public SGReferenced
|
||||
{
|
||||
public:
|
||||
|
||||
FGPanel ();
|
||||
virtual ~FGPanel ();
|
||||
|
||||
virtual void draw (osg::State& state);
|
||||
|
||||
virtual void updateMouseDelay(double dt);
|
||||
|
||||
// transfer pointer ownership!!!
|
||||
virtual void addInstrument (FGPanelInstrument * instrument);
|
||||
|
||||
// Background texture.
|
||||
virtual void setBackground (osg::Texture2D* texture);
|
||||
|
||||
// Background multiple textures.
|
||||
virtual void setMultiBackground (osg::Texture2D* texture, int idx);
|
||||
|
||||
virtual void setWidth (int width) { _width = width; }
|
||||
virtual int getWidth () const { return _width; }
|
||||
|
||||
// Full height of panel.
|
||||
virtual void setHeight (int height) { _height = height; }
|
||||
virtual int getHeight () const { return _height; }
|
||||
|
||||
// X-offset
|
||||
virtual void setXOffset (int offset);
|
||||
virtual int getXOffset () const { return _x_offset->getIntValue(); }
|
||||
|
||||
// Y-offset.
|
||||
virtual void setYOffset (int offset);
|
||||
virtual int getYOffset () const { return _y_offset->getIntValue(); }
|
||||
|
||||
// View height.
|
||||
// virtual void setViewHeight (int height) { _view_height = height; }
|
||||
// virtual int getViewHeight () const { return _view_height; }
|
||||
|
||||
/**
|
||||
* find the actual logical extend of the panel, including all instruments
|
||||
* and actions.
|
||||
*/
|
||||
void getLogicalExtent(int &x0, int& y0, int& x1, int &y1);
|
||||
|
||||
// Handle a mouse click.
|
||||
virtual bool doMouseAction (int button, int updown, int x, int y);
|
||||
virtual bool doLocalMouseAction(int button, int updown, int x, int y);
|
||||
|
||||
virtual void setDepthTest (bool enable);
|
||||
|
||||
bool getAutohide(void) const { return _autohide; };
|
||||
void setAutohide(bool enable) { _autohide = enable; };
|
||||
|
||||
double getAspectScale() const;
|
||||
|
||||
private:
|
||||
void setupVirtualCockpit();
|
||||
void cleanupVirtualCockpit();
|
||||
|
||||
mutable bool _mouseDown;
|
||||
mutable int _mouseButton, _mouseX, _mouseY;
|
||||
double _mouseActionRepeat;
|
||||
|
||||
mutable FGPanelInstrument * _mouseInstrument;
|
||||
typedef std::vector<FGPanelInstrument *> instrument_list_type;
|
||||
int _width;
|
||||
int _height;
|
||||
// int _view_height;
|
||||
|
||||
SGPropertyNode_ptr _x_offset;
|
||||
SGPropertyNode_ptr _y_offset;
|
||||
SGPropertyNode_ptr _jitter;
|
||||
SGPropertyNode_ptr _flipx;
|
||||
|
||||
SGConstPropertyNode_ptr _xsize_node;
|
||||
SGConstPropertyNode_ptr _ysize_node;
|
||||
|
||||
osg::ref_ptr<osg::StateSet> _bg;
|
||||
osg::ref_ptr<osg::StateSet> _mbg[8];
|
||||
// List of instruments in panel.
|
||||
instrument_list_type _instruments;
|
||||
bool _enable_depth_test;
|
||||
bool _autohide;
|
||||
|
||||
SGPropObjBool _drawPanelHotspots;
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Actions
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Class for user actions.
|
||||
*
|
||||
* The actions are command bindings, like bindings for the keyboard
|
||||
* or joystick, but they are tied to specific mouse actions in
|
||||
* rectangular areas of the panel.
|
||||
*/
|
||||
class FGPanelAction : public SGConditional
|
||||
{
|
||||
public:
|
||||
FGPanelAction ();
|
||||
FGPanelAction (int button, int x, int y, int w, int h, bool repeatable);
|
||||
virtual ~FGPanelAction ();
|
||||
|
||||
// Getters.
|
||||
virtual int getButton () const { return _button; }
|
||||
virtual int getX () const { return _x; }
|
||||
virtual int getY () const { return _y; }
|
||||
virtual int getWidth () const { return _w; }
|
||||
virtual int getHeight () const { return _h; }
|
||||
|
||||
// Setters.
|
||||
|
||||
// transfer pointer ownership
|
||||
virtual void addBinding (SGBinding * binding, int updown);
|
||||
virtual void setButton (int button) { _button = button; }
|
||||
virtual void setX (int x) { _x = x; }
|
||||
virtual void setY (int y) { _y = y; }
|
||||
virtual void setWidth (int w) { _w = w; }
|
||||
virtual void setHeight (int h) { _h = h; }
|
||||
|
||||
// Check whether we're in the area.
|
||||
virtual bool inArea (int button, int x, int y)
|
||||
{
|
||||
return (button == _button &&
|
||||
x >= _x &&
|
||||
x < _x + _w &&
|
||||
y >= _y &&
|
||||
y < _y + _h);
|
||||
}
|
||||
|
||||
// Perform the action.
|
||||
virtual bool doAction (int updown);
|
||||
|
||||
private:
|
||||
typedef std::vector<SGBinding *> binding_list_t;
|
||||
|
||||
int _button;
|
||||
int _x;
|
||||
int _y;
|
||||
int _w;
|
||||
int _h;
|
||||
bool _repeatable;
|
||||
int _last_state;
|
||||
binding_list_t _bindings[2];
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Transformations.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* A transformation for a layer.
|
||||
*/
|
||||
class FGPanelTransformation : public SGConditional
|
||||
{
|
||||
public:
|
||||
|
||||
enum Type {
|
||||
XSHIFT,
|
||||
YSHIFT,
|
||||
ROTATION
|
||||
};
|
||||
|
||||
FGPanelTransformation ();
|
||||
virtual ~FGPanelTransformation ();
|
||||
|
||||
Type type;
|
||||
SGConstPropertyNode_ptr node;
|
||||
float min;
|
||||
float max;
|
||||
bool has_mod;
|
||||
float mod;
|
||||
float factor;
|
||||
float offset;
|
||||
SGInterpTable * table;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Layers
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* A single layer of a multi-layered instrument.
|
||||
*
|
||||
* Each layer can be subject to a series of transformations based
|
||||
* on current FGFS instrument readings: for example, a texture
|
||||
* representing a needle can rotate to show the airspeed.
|
||||
*/
|
||||
class FGInstrumentLayer : public SGConditional
|
||||
{
|
||||
public:
|
||||
|
||||
FGInstrumentLayer (int w = -1, int h = -1);
|
||||
virtual ~FGInstrumentLayer ();
|
||||
|
||||
virtual void draw (osg::State& state) = 0;
|
||||
virtual void transform () const;
|
||||
|
||||
virtual int getWidth () const { return _w; }
|
||||
virtual int getHeight () const { return _h; }
|
||||
virtual void setWidth (int w) { _w = w; }
|
||||
virtual void setHeight (int h) { _h = h; }
|
||||
|
||||
// Transfer pointer ownership!!
|
||||
// DEPRECATED
|
||||
virtual void addTransformation (FGPanelTransformation * transformation);
|
||||
|
||||
protected:
|
||||
int _w, _h;
|
||||
|
||||
typedef std::vector<FGPanelTransformation *> transformation_list;
|
||||
transformation_list _transformations;
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Instruments.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Abstract base class for a panel instrument.
|
||||
*
|
||||
* A panel instrument consists of zero or more actions, associated
|
||||
* with mouse clicks in rectangular areas. Currently, the only
|
||||
* concrete class derived from this is FGLayeredInstrument, but others
|
||||
* may show up in the future (some complex instruments could be
|
||||
* entirely hand-coded, for example).
|
||||
*/
|
||||
class FGPanelInstrument : public SGConditional
|
||||
{
|
||||
public:
|
||||
FGPanelInstrument ();
|
||||
FGPanelInstrument (int x, int y, int w, int h);
|
||||
virtual ~FGPanelInstrument ();
|
||||
|
||||
virtual void draw (osg::State& state) = 0;
|
||||
virtual void drawHotspots(osg::State& state);
|
||||
|
||||
virtual void setPosition(int x, int y);
|
||||
virtual void setSize(int w, int h);
|
||||
|
||||
virtual int getXPos () const;
|
||||
virtual int getYPos () const;
|
||||
virtual int getWidth () const;
|
||||
virtual int getHeight () const;
|
||||
|
||||
// Coordinates relative to centre.
|
||||
// Transfer pointer ownership!!
|
||||
virtual void addAction (FGPanelAction * action);
|
||||
|
||||
// Coordinates relative to centre.
|
||||
virtual bool doMouseAction (int button, int updown, int x, int y);
|
||||
|
||||
void extendRect(IntRect& r) const;
|
||||
protected:
|
||||
int _x, _y, _w, _h;
|
||||
typedef std::vector<FGPanelAction *> action_list_type;
|
||||
action_list_type _actions;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An instrument constructed of multiple layers.
|
||||
*
|
||||
* Each individual layer can be rotated or shifted to correspond
|
||||
* to internal FGFS instrument readings.
|
||||
*/
|
||||
class FGLayeredInstrument : public FGPanelInstrument
|
||||
{
|
||||
public:
|
||||
FGLayeredInstrument (int x, int y, int w, int h);
|
||||
virtual ~FGLayeredInstrument ();
|
||||
|
||||
virtual void draw (osg::State& state);
|
||||
|
||||
// Transfer pointer ownership!!
|
||||
virtual int addLayer (FGInstrumentLayer *layer);
|
||||
virtual int addLayer (const FGCroppedTexture &texture, int w = -1, int h = -1);
|
||||
|
||||
// Transfer pointer ownership!!
|
||||
virtual void addTransformation (FGPanelTransformation * transformation);
|
||||
|
||||
protected:
|
||||
typedef std::vector<FGInstrumentLayer *> layer_list;
|
||||
layer_list _layers;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An empty-shell instrument that exists soley in
|
||||
* order to redirect commands from the panel to a
|
||||
* complex instrument inherited from SGSubsystem.
|
||||
*
|
||||
* Currently the only complex instrument is the KLN89,
|
||||
* which we've hardwired this to for now.
|
||||
*/
|
||||
class FGSpecialInstrument : public FGPanelInstrument
|
||||
{
|
||||
public:
|
||||
FGSpecialInstrument(DCLGPS* sb);
|
||||
//FGSpecialInstrument (int x, int y, int w, int h);
|
||||
virtual ~FGSpecialInstrument ();
|
||||
|
||||
virtual void draw (osg::State& state);
|
||||
|
||||
protected:
|
||||
DCLGPS* complex;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An instrument layer containing a group of sublayers.
|
||||
*
|
||||
* This class is useful for gathering together a group of related
|
||||
* layers, either to hold in an external file or to work under
|
||||
* the same condition.
|
||||
*/
|
||||
class FGGroupLayer : public FGInstrumentLayer
|
||||
{
|
||||
public:
|
||||
FGGroupLayer ();
|
||||
virtual ~FGGroupLayer ();
|
||||
virtual void draw (osg::State& state);
|
||||
// transfer pointer ownership
|
||||
virtual void addLayer (FGInstrumentLayer * layer);
|
||||
protected:
|
||||
std::vector<FGInstrumentLayer *> _layers;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A textured layer of an instrument.
|
||||
*
|
||||
* This is a layer holding a single texture. Normally, the texture's
|
||||
* backgound should be transparent so that lower layers and the panel
|
||||
* background can show through.
|
||||
*/
|
||||
class FGTexturedLayer : public FGInstrumentLayer
|
||||
{
|
||||
public:
|
||||
FGTexturedLayer (int w = -1, int h = -1) : FGInstrumentLayer(w, h) {}
|
||||
FGTexturedLayer (const FGCroppedTexture &texture, int w = -1, int h = -1);
|
||||
virtual ~FGTexturedLayer ();
|
||||
|
||||
virtual void draw (osg::State& state);
|
||||
|
||||
virtual void setTexture (const FGCroppedTexture &texture) {
|
||||
_texture = texture;
|
||||
}
|
||||
virtual const FGCroppedTexture &getTexture () const { return _texture; }
|
||||
virtual FGCroppedTexture *getTexture() { return &_texture; }
|
||||
|
||||
void setEmissive(bool e) { _emissive = e; }
|
||||
|
||||
private:
|
||||
FGCroppedTexture _texture;
|
||||
bool _emissive;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A text layer of an instrument.
|
||||
*
|
||||
* This is a layer holding a string of static and/or generated text.
|
||||
* It is useful for instruments that have text displays, such as
|
||||
* a chronometer, GPS, or NavCom radio.
|
||||
*/
|
||||
class FGTextLayer : public FGInstrumentLayer
|
||||
{
|
||||
public:
|
||||
enum ChunkType {
|
||||
TEXT,
|
||||
TEXT_VALUE,
|
||||
DOUBLE_VALUE
|
||||
};
|
||||
|
||||
class Chunk : public SGConditional
|
||||
{
|
||||
public:
|
||||
Chunk (const std::string &text, const std::string &fmt = "%s");
|
||||
Chunk (ChunkType type, const SGPropertyNode * node,
|
||||
const std::string &fmt = "", float mult = 1.0, float offs = 0.0,
|
||||
bool truncation = false);
|
||||
|
||||
const char * getValue () const;
|
||||
private:
|
||||
ChunkType _type;
|
||||
std::string _text;
|
||||
SGConstPropertyNode_ptr _node;
|
||||
std::string _fmt;
|
||||
float _mult;
|
||||
float _offs;
|
||||
bool _trunc;
|
||||
mutable char _buf[1024];
|
||||
};
|
||||
|
||||
FGTextLayer (int w = -1, int h = -1);
|
||||
virtual ~FGTextLayer ();
|
||||
|
||||
virtual void draw (osg::State& state);
|
||||
|
||||
// Transfer pointer!!
|
||||
virtual void addChunk (Chunk * chunk);
|
||||
virtual void setColor (float r, float g, float b);
|
||||
virtual void setPointSize (float size);
|
||||
virtual void setFontName ( const std::string &name );
|
||||
virtual void setFont (fntFont * font);
|
||||
|
||||
private:
|
||||
|
||||
void recalc_value () const;
|
||||
|
||||
typedef std::vector<Chunk *> chunk_list;
|
||||
chunk_list _chunks;
|
||||
float _color[4];
|
||||
|
||||
float _pointSize;
|
||||
mutable std::string _font_name;
|
||||
mutable std::string _value;
|
||||
mutable SGTimeStamp _then;
|
||||
mutable SGTimeStamp _now;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A group layer that switches among its children.
|
||||
*
|
||||
* The first layer that passes its condition will be drawn, and
|
||||
* any following layers will be ignored.
|
||||
*/
|
||||
class FGSwitchLayer : public FGGroupLayer
|
||||
{
|
||||
public:
|
||||
// Transfer pointers!!
|
||||
FGSwitchLayer ();
|
||||
virtual void draw (osg::State& state);
|
||||
|
||||
};
|
||||
#endif // __PANEL_HXX
|
||||
|
||||
// end of panel.hxx
|
||||
|
||||
|
||||
|
||||
868
src/Cockpit/panel_io.cxx
Normal file
868
src/Cockpit/panel_io.cxx
Normal file
@@ -0,0 +1,868 @@
|
||||
// panel_io.cxx - I/O for 2D panel.
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <string.h> // for strcmp()
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/props/props_io.hxx>
|
||||
#include <simgear/debug/ErrorReportingCallback.hxx>
|
||||
|
||||
#include <istream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Main/sentryIntegration.hxx>
|
||||
|
||||
#include <GUI/gui.h>
|
||||
|
||||
// #include "panel.hxx"
|
||||
#include "panel_io.hxx"
|
||||
#include <Instrumentation/KLN89/kln89.hxx>
|
||||
|
||||
//built-in layers
|
||||
#include "built_in/FGMagRibbon.hxx"
|
||||
|
||||
using std::istream;
|
||||
using std::ifstream;
|
||||
using std::string;
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Read and construct a panel.
|
||||
//
|
||||
// The panel is specified as a regular property list, and each of the
|
||||
// instruments is its own, separate property list (and thus, a separate
|
||||
// XML document). The functions in this section read in the files
|
||||
// as property lists, then extract properties to set up the panel
|
||||
// itself.
|
||||
//
|
||||
// A panel contains zero or more instruments.
|
||||
//
|
||||
// An instrument contains one or more layers and zero or more actions.
|
||||
//
|
||||
// A layer contains zero or more transformations.
|
||||
//
|
||||
// Some special types of layers also contain other objects, such as
|
||||
// chunks of text or other layers.
|
||||
//
|
||||
// There are currently four types of layers:
|
||||
//
|
||||
// 1. Textured Layer (type="texture"), the default
|
||||
// 2. Text Layer (type="text")
|
||||
// 3. Switch Layer (type="switch")
|
||||
// 4. Built-in Layer (type="built-in", must also specify class)
|
||||
//
|
||||
// The only built-in layer so far is the ribbon for the magnetic compass
|
||||
// (class="compass-ribbon").
|
||||
//
|
||||
// There are three types of actions:
|
||||
//
|
||||
// 1. Adjust (type="adjust"), the default
|
||||
// 2. Swap (type="swap")
|
||||
// 3. Toggle (type="toggle")
|
||||
//
|
||||
// There are three types of transformations:
|
||||
//
|
||||
// 1. X shift (type="x-shift"), the default
|
||||
// 2. Y shift (type="y-shift")
|
||||
// 3. Rotation (type="rotation")
|
||||
//
|
||||
// Each of these may be associated with a property, so that a needle
|
||||
// will rotate with the airspeed, for example, or may have a fixed
|
||||
// floating-point value.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Read a cropped texture from the instrument's property list.
|
||||
*
|
||||
* The x1 and y1 properties give the starting position of the texture
|
||||
* (between 0.0 and 1.0), and the the x2 and y2 properties give the
|
||||
* ending position. For example, to use the bottom-left quarter of a
|
||||
* texture, x1=0.0, y1=0.0, x2=0.5, y2=0.5.
|
||||
*/
|
||||
static FGCroppedTexture
|
||||
readTexture (const SGPropertyNode * node)
|
||||
{
|
||||
FGCroppedTexture texture(node->getStringValue("path"),
|
||||
node->getFloatValue("x1"),
|
||||
node->getFloatValue("y1"),
|
||||
node->getFloatValue("x2", 1.0),
|
||||
node->getFloatValue("y2", 1.0));
|
||||
SG_LOG(SG_COCKPIT, SG_DEBUG, "Read texture " << node->getNameString());
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test for a condition in the current node.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Read a condition and use it if necessary.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void
|
||||
readConditions (SGConditional *component, const SGPropertyNode *node)
|
||||
{
|
||||
const SGPropertyNode * conditionNode = node->getChild("condition");
|
||||
if (conditionNode != 0)
|
||||
// The top level is implicitly AND
|
||||
component->setCondition(sgReadCondition(globals->get_props(),
|
||||
conditionNode) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read an action from the instrument's property list.
|
||||
*
|
||||
* The action will be performed when the user clicks a mouse button
|
||||
* within the specified region of the instrument. Actions always work
|
||||
* by modifying the value of a property (see the SGPropertyNode
|
||||
* class).
|
||||
*
|
||||
* The following action types are defined:
|
||||
*
|
||||
* "adjust" - modify the value of a floating-point property by
|
||||
* the increment specified. This is the default.
|
||||
*
|
||||
* "swap" - swap the values of two-floating-point properties.
|
||||
*
|
||||
* "toggle" - toggle the value of a boolean property between true and
|
||||
* false.
|
||||
*
|
||||
* For the adjust action, it is possible to specify an increment
|
||||
* (use a negative number for a decrement), a minimum allowed value,
|
||||
* a maximum allowed value, and a flag to indicate whether the value
|
||||
* should freeze or wrap-around when it reachs the minimum or maximum.
|
||||
*
|
||||
* The action will be scaled automatically if the instrument is not
|
||||
* being drawn at its regular size.
|
||||
*/
|
||||
static FGPanelAction *
|
||||
readAction (const SGPropertyNode * node, float w_scale, float h_scale)
|
||||
{
|
||||
unsigned int i, j;
|
||||
SGPropertyNode *binding;
|
||||
vector<SGPropertyNode_ptr>bindings = node->getChildren("binding");
|
||||
|
||||
// button-less actions are fired initially
|
||||
if (!node->hasValue("w") || !node->hasValue("h")) {
|
||||
for (i = 0; i < bindings.size(); i++) {
|
||||
SGBinding b(bindings[i], globals->get_props());
|
||||
b.fire();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
string name = node->getStringValue("name");
|
||||
|
||||
int button = node->getIntValue("button");
|
||||
int x = int(node->getIntValue("x") * w_scale);
|
||||
int y = int(node->getIntValue("y") * h_scale);
|
||||
int w = int(node->getIntValue("w") * w_scale);
|
||||
int h = int(node->getIntValue("h") * h_scale);
|
||||
bool repeatable = node->getBoolValue("repeatable", true);
|
||||
|
||||
FGPanelAction * action = new FGPanelAction(button, x, y, w, h, repeatable);
|
||||
|
||||
SGPropertyNode * dest = fgGetNode("/sim/bindings/panel", true);
|
||||
|
||||
for (i = 0; i < bindings.size(); i++) {
|
||||
SG_LOG(SG_INPUT, SG_BULK, "Reading binding "
|
||||
<< bindings[i]->getStringValue("command"));
|
||||
|
||||
j = 0;
|
||||
while (dest->getChild("binding", j))
|
||||
j++;
|
||||
|
||||
binding = dest->getChild("binding", j, true);
|
||||
copyProperties(bindings[i], binding);
|
||||
action->addBinding(new SGBinding(binding, globals->get_props()), 0);
|
||||
}
|
||||
|
||||
if (node->hasChild("mod-up")) {
|
||||
bindings = node->getChild("mod-up")->getChildren("binding");
|
||||
for (i = 0; i < bindings.size(); i++) {
|
||||
j = 0;
|
||||
while (dest->getChild("binding", j))
|
||||
j++;
|
||||
|
||||
binding = dest->getChild("binding", j, true);
|
||||
copyProperties(bindings[i], binding);
|
||||
action->addBinding(new SGBinding(binding, globals->get_props()), 1);
|
||||
}
|
||||
}
|
||||
|
||||
readConditions(action, node);
|
||||
return action;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a transformation from the instrument's property list.
|
||||
*
|
||||
* The panel module uses the transformations to slide or spin needles,
|
||||
* knobs, and other indicators, and to place layers in the correct
|
||||
* positions. Every layer starts centered exactly on the x,y co-ordinate,
|
||||
* and many layers need to be moved or rotated simply to display the
|
||||
* instrument correctly.
|
||||
*
|
||||
* There are three types of transformations:
|
||||
*
|
||||
* "x-shift" - move the layer horizontally.
|
||||
*
|
||||
* "y-shift" - move the layer vertically.
|
||||
*
|
||||
* "rotation" - rotate the layer.
|
||||
*
|
||||
* Each transformation may have a fixed offset, and may also have
|
||||
* a floating-point property value to add to the offset. The
|
||||
* floating-point property may be clamped to a minimum and/or
|
||||
* maximum range and scaled (after clamping).
|
||||
*
|
||||
* Note that because of the way OpenGL works, transformations will
|
||||
* appear to be applied backwards.
|
||||
*/
|
||||
static FGPanelTransformation *
|
||||
readTransformation (const SGPropertyNode * node, float w_scale, float h_scale)
|
||||
{
|
||||
FGPanelTransformation * t = new FGPanelTransformation;
|
||||
|
||||
string name = node->getNameString();
|
||||
string type = node->getStringValue("type");
|
||||
string propName = node->getStringValue("property", "");
|
||||
SGPropertyNode * target = 0;
|
||||
|
||||
if (type.empty()) {
|
||||
SG_LOG( SG_COCKPIT, SG_BULK,
|
||||
"No type supplied for transformation " << name
|
||||
<< " assuming \"rotation\"" );
|
||||
type = "rotation";
|
||||
}
|
||||
|
||||
if (!propName.empty()) {
|
||||
target = fgGetNode(propName.c_str(), true);
|
||||
}
|
||||
|
||||
t->node = target;
|
||||
t->min = node->getFloatValue("min", -9999999);
|
||||
t->max = node->getFloatValue("max", 99999999);
|
||||
t->has_mod = node->hasChild("modulator");
|
||||
if (t->has_mod)
|
||||
t->mod = node->getFloatValue("modulator");
|
||||
t->factor = node->getFloatValue("scale", 1.0);
|
||||
t->offset = node->getFloatValue("offset", 0.0);
|
||||
|
||||
// Check for an interpolation table
|
||||
const SGPropertyNode * trans_table = node->getNode("interpolation");
|
||||
if (trans_table != 0) {
|
||||
SG_LOG( SG_COCKPIT, SG_DEBUG, "Found interpolation table with "
|
||||
<< trans_table->nChildren() << " children" );
|
||||
t->table = new SGInterpTable(trans_table);
|
||||
} else {
|
||||
t->table = 0;
|
||||
}
|
||||
|
||||
// Move the layer horizontally.
|
||||
if (type == "x-shift") {
|
||||
t->type = FGPanelTransformation::XSHIFT;
|
||||
// t->min *= w_scale; //removed by Martin Dressler
|
||||
// t->max *= w_scale; //removed by Martin Dressler
|
||||
t->offset *= w_scale;
|
||||
t->factor *= w_scale; //Added by Martin Dressler
|
||||
}
|
||||
|
||||
// Move the layer vertically.
|
||||
else if (type == "y-shift") {
|
||||
t->type = FGPanelTransformation::YSHIFT;
|
||||
//t->min *= h_scale; //removed
|
||||
//t->max *= h_scale; //removed
|
||||
t->offset *= h_scale;
|
||||
t->factor *= h_scale; //Added
|
||||
}
|
||||
|
||||
// Rotate the layer. The rotation
|
||||
// is in degrees, and does not need
|
||||
// to scale with the instrument size.
|
||||
else if (type == "rotation") {
|
||||
t->type = FGPanelTransformation::ROTATION;
|
||||
}
|
||||
|
||||
else {
|
||||
SG_LOG( SG_COCKPIT, SG_ALERT, "Unrecognized transformation type " << type );
|
||||
delete t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
readConditions(t, node);
|
||||
SG_LOG( SG_COCKPIT, SG_DEBUG, "Read transformation " << name );
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a chunk of text from the instrument's property list.
|
||||
*
|
||||
* A text layer consists of one or more chunks of text. All chunks
|
||||
* share the same font size and color (and eventually, font), but
|
||||
* each can come from a different source. There are three types of
|
||||
* text chunks:
|
||||
*
|
||||
* "literal" - a literal text string (the default)
|
||||
*
|
||||
* "text-value" - the current value of a string property
|
||||
*
|
||||
* "number-value" - the current value of a floating-point property.
|
||||
*
|
||||
* All three may also include a printf-style format string.
|
||||
*/
|
||||
FGTextLayer::Chunk *
|
||||
readTextChunk (const SGPropertyNode * node)
|
||||
{
|
||||
FGTextLayer::Chunk * chunk;
|
||||
string name = node->getStringValue("name");
|
||||
string type = node->getStringValue("type");
|
||||
string format = node->getStringValue("format");
|
||||
|
||||
// Default to literal text.
|
||||
if (type.empty()) {
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "No type provided for text chunk " << name
|
||||
<< " assuming \"literal\"");
|
||||
type = "literal";
|
||||
}
|
||||
|
||||
// A literal text string.
|
||||
if (type == "literal") {
|
||||
string text = node->getStringValue("text");
|
||||
chunk = new FGTextLayer::Chunk(text, format);
|
||||
}
|
||||
|
||||
// The value of a string property.
|
||||
else if (type == "text-value") {
|
||||
SGPropertyNode * target =
|
||||
fgGetNode(node->getStringValue("property"), true);
|
||||
chunk = new FGTextLayer::Chunk(FGTextLayer::TEXT_VALUE, target, format);
|
||||
}
|
||||
|
||||
// The value of a float property.
|
||||
else if (type == "number-value") {
|
||||
string propName = node->getStringValue("property");
|
||||
float scale = node->getFloatValue("scale", 1.0);
|
||||
float offset = node->getFloatValue("offset", 0.0);
|
||||
bool truncation = node->getBoolValue("truncate", false);
|
||||
SGPropertyNode * target = fgGetNode(propName.c_str(), true);
|
||||
chunk = new FGTextLayer::Chunk(FGTextLayer::DOUBLE_VALUE, target,
|
||||
format, scale, offset, truncation);
|
||||
}
|
||||
|
||||
// Unknown type.
|
||||
else {
|
||||
SG_LOG( SG_COCKPIT, SG_ALERT, "Unrecognized type " << type
|
||||
<< " for text chunk " << name );
|
||||
return 0;
|
||||
}
|
||||
|
||||
readConditions(chunk, node);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a single layer from an instrument's property list.
|
||||
*
|
||||
* Each instrument consists of one or more layers stacked on top
|
||||
* of each other; the lower layers show through only where the upper
|
||||
* layers contain an alpha component. Each layer can be moved
|
||||
* horizontally and vertically and rotated using transformations.
|
||||
*
|
||||
* This module currently recognizes four kinds of layers:
|
||||
*
|
||||
* "texture" - a layer containing a texture (the default)
|
||||
*
|
||||
* "text" - a layer containing text
|
||||
*
|
||||
* "switch" - a layer that switches between two other layers
|
||||
* based on the current value of a boolean property.
|
||||
*
|
||||
* "built-in" - a hard-coded layer supported by C++ code in FlightGear.
|
||||
*
|
||||
* Currently, the only built-in layer class is "compass-ribbon".
|
||||
*/
|
||||
static FGInstrumentLayer *
|
||||
readLayer (const SGPropertyNode * node, float w_scale, float h_scale)
|
||||
{
|
||||
FGInstrumentLayer * layer = NULL;
|
||||
string name = node->getStringValue("name");
|
||||
string type = node->getStringValue("type");
|
||||
int w = node->getIntValue("w", -1);
|
||||
int h = node->getIntValue("h", -1);
|
||||
bool emissive = node->getBoolValue("emissive", false);
|
||||
if (w != -1)
|
||||
w = int(w * w_scale);
|
||||
if (h != -1)
|
||||
h = int(h * h_scale);
|
||||
|
||||
|
||||
if (type.empty()) {
|
||||
SG_LOG( SG_COCKPIT, SG_BULK,
|
||||
"No type supplied for layer " << name
|
||||
<< " assuming \"texture\"" );
|
||||
type = "texture";
|
||||
}
|
||||
|
||||
|
||||
// A textured instrument layer.
|
||||
if (type == "texture") {
|
||||
FGCroppedTexture texture = readTexture(node->getNode("texture"));
|
||||
layer = new FGTexturedLayer(texture, w, h);
|
||||
if (emissive) {
|
||||
FGTexturedLayer *tl=(FGTexturedLayer*)layer;
|
||||
tl->setEmissive(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// A group of sublayers.
|
||||
else if (type == "group") {
|
||||
layer = new FGGroupLayer();
|
||||
for (int i = 0; i < node->nChildren(); i++) {
|
||||
const SGPropertyNode * child = node->getChild(i);
|
||||
if (child->getNameString() == "layer")
|
||||
((FGGroupLayer *)layer)->addLayer(readLayer(child, w_scale, h_scale));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A textual instrument layer.
|
||||
else if (type == "text") {
|
||||
FGTextLayer * tlayer = new FGTextLayer(w, h); // FIXME
|
||||
|
||||
// Set the text color.
|
||||
float red = node->getFloatValue("color/red", 0.0);
|
||||
float green = node->getFloatValue("color/green", 0.0);
|
||||
float blue = node->getFloatValue("color/blue", 0.0);
|
||||
tlayer->setColor(red, green, blue);
|
||||
|
||||
// Set the point size.
|
||||
float pointSize = node->getFloatValue("point-size", 10.0) * w_scale;
|
||||
tlayer->setPointSize(pointSize);
|
||||
|
||||
// Set the font.
|
||||
string fontName = node->getStringValue("font", "Helvetica");
|
||||
tlayer->setFontName(fontName);
|
||||
|
||||
const SGPropertyNode * chunk_group = node->getNode("chunks");
|
||||
if (chunk_group != 0) {
|
||||
int nChunks = chunk_group->nChildren();
|
||||
for (int i = 0; i < nChunks; i++) {
|
||||
const SGPropertyNode * node = chunk_group->getChild(i);
|
||||
if (node->getNameString() == "chunk") {
|
||||
FGTextLayer::Chunk * chunk = readTextChunk(node);
|
||||
if (chunk != 0)
|
||||
tlayer->addChunk(chunk);
|
||||
} else {
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getNameString()
|
||||
<< " in chunks" );
|
||||
}
|
||||
}
|
||||
layer = tlayer;
|
||||
}
|
||||
}
|
||||
|
||||
// A switch instrument layer.
|
||||
else if (type == "switch") {
|
||||
layer = new FGSwitchLayer();
|
||||
for (int i = 0; i < node->nChildren(); i++) {
|
||||
const SGPropertyNode * child = node->getChild(i);
|
||||
if (child->getNameString() == "layer")
|
||||
((FGGroupLayer *)layer)->addLayer(readLayer(child, w_scale, h_scale));
|
||||
}
|
||||
}
|
||||
|
||||
// A built-in instrument layer.
|
||||
else if (type == "built-in") {
|
||||
string layerclass = node->getStringValue("class");
|
||||
|
||||
if (layerclass == "mag-ribbon") {
|
||||
layer = new FGMagRibbon(w, h);
|
||||
}
|
||||
|
||||
else if (layerclass.empty()) {
|
||||
SG_LOG( SG_COCKPIT, SG_ALERT, "No class provided for built-in layer "
|
||||
<< name );
|
||||
return 0;
|
||||
}
|
||||
|
||||
else {
|
||||
SG_LOG( SG_COCKPIT, SG_ALERT, "Unknown built-in layer class "
|
||||
<< layerclass);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// An unknown type.
|
||||
else {
|
||||
SG_LOG( SG_COCKPIT, SG_ALERT, "Unrecognized layer type " << type );
|
||||
delete layer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the transformations for each layer.
|
||||
//
|
||||
const SGPropertyNode * trans_group = node->getNode("transformations");
|
||||
if (trans_group != 0) {
|
||||
int nTransformations = trans_group->nChildren();
|
||||
for (int i = 0; i < nTransformations; i++) {
|
||||
const SGPropertyNode * node = trans_group->getChild(i);
|
||||
if (node->getNameString() == "transformation") {
|
||||
FGPanelTransformation * t = readTransformation(node, w_scale, h_scale);
|
||||
if (t != 0)
|
||||
layer->addTransformation(t);
|
||||
} else {
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getNameString()
|
||||
<< " in transformations" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readConditions(layer, node);
|
||||
SG_LOG( SG_COCKPIT, SG_DEBUG, "Read layer " << name );
|
||||
return layer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read an instrument from a property list.
|
||||
*
|
||||
* The instrument consists of a preferred width and height
|
||||
* (the panel may override these), together with a list of layers
|
||||
* and a list of actions to be performed when the user clicks
|
||||
* the mouse over the instrument. All co-ordinates are relative
|
||||
* to the instrument's position, so instruments are fully relocatable;
|
||||
* likewise, co-ordinates for actions and transformations will be
|
||||
* scaled automatically if the instrument is not at its preferred size.
|
||||
*/
|
||||
static FGPanelInstrument *
|
||||
readInstrument (const SGPropertyNode * node, const SGPath& path)
|
||||
{
|
||||
const string name = node->getStringValue("name");
|
||||
int x = node->getIntValue("x", -1);
|
||||
int y = node->getIntValue("y", -1);
|
||||
int real_w = node->getIntValue("w", -1);
|
||||
int real_h = node->getIntValue("h", -1);
|
||||
int w = node->getIntValue("w-base", -1);
|
||||
int h = node->getIntValue("h-base", -1);
|
||||
|
||||
if (x == -1 || y == -1) {
|
||||
simgear::reportFailure(simgear::LoadFailure::Misconfigured, simgear::ErrorCode::AircraftSystems,
|
||||
"Panel x and y positions must be specified and > 0", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
float w_scale = 1.0;
|
||||
float h_scale = 1.0;
|
||||
if (real_w != -1) {
|
||||
w_scale = float(real_w) / float(w);
|
||||
w = real_w;
|
||||
}
|
||||
if (real_h != -1) {
|
||||
h_scale = float(real_h) / float(h);
|
||||
h = real_h;
|
||||
}
|
||||
|
||||
SG_LOG( SG_COCKPIT, SG_DEBUG, "Reading instrument " << name );
|
||||
|
||||
FGLayeredInstrument * instrument =
|
||||
new FGLayeredInstrument(x, y, w, h);
|
||||
|
||||
//
|
||||
// Get the actions for the instrument.
|
||||
//
|
||||
const SGPropertyNode * action_group = node->getNode("actions");
|
||||
if (action_group != 0) {
|
||||
int nActions = action_group->nChildren();
|
||||
for (int i = 0; i < nActions; i++) {
|
||||
const SGPropertyNode * node = action_group->getChild(i);
|
||||
if (node->getNameString() == "action") {
|
||||
FGPanelAction * action = readAction(node, w_scale, h_scale);
|
||||
if (action != 0)
|
||||
instrument->addAction(action);
|
||||
} else {
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getNameString()
|
||||
<< " in actions" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Get the layers for the instrument.
|
||||
//
|
||||
const SGPropertyNode * layer_group = node->getNode("layers");
|
||||
if (layer_group != 0) {
|
||||
int nLayers = layer_group->nChildren();
|
||||
for (int i = 0; i < nLayers; i++) {
|
||||
const SGPropertyNode * node = layer_group->getChild(i);
|
||||
if (node->getNameString() == "layer") {
|
||||
FGInstrumentLayer * layer = readLayer(node, w_scale, h_scale);
|
||||
if (layer != 0)
|
||||
instrument->addLayer(layer);
|
||||
} else {
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getNameString()
|
||||
<< " in layers" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readConditions(instrument, node);
|
||||
return instrument;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct the panel from a property tree.
|
||||
*/
|
||||
FGPanel *
|
||||
readPanel (const SGPropertyNode * root, const SGPath& path)
|
||||
{
|
||||
SG_LOG( SG_COCKPIT, SG_INFO, "Reading properties for panel " <<
|
||||
root->getStringValue("name", "[Unnamed Panel]") );
|
||||
|
||||
FGPanel * panel = new FGPanel();
|
||||
panel->setWidth(root->getIntValue("w", 1024));
|
||||
panel->setHeight(root->getIntValue("h", 443));
|
||||
|
||||
//
|
||||
// Grab the visible external viewing area, default to
|
||||
//
|
||||
// panel->setViewHeight(root->getIntValue("view-height",
|
||||
// 768 - panel->getHeight() + 2));
|
||||
|
||||
//
|
||||
// Grab the panel's initial offsets, default to 0, 0.
|
||||
//
|
||||
if (!fgHasNode("/sim/panel/x-offset"))
|
||||
fgSetInt("/sim/panel/x-offset", root->getIntValue("x-offset", 0));
|
||||
|
||||
// conditional removed by jim wilson to allow panel xml code
|
||||
// with y-offset defined to work...
|
||||
if (!fgHasNode("/sim/panel/y-offset"))
|
||||
fgSetInt("/sim/panel/y-offset", root->getIntValue("y-offset", 0));
|
||||
|
||||
panel->setAutohide(root->getBoolValue("autohide", true));
|
||||
|
||||
//
|
||||
// Assign the background texture, if any, or a bogus chequerboard.
|
||||
//
|
||||
string bgTexture = root->getStringValue("background");
|
||||
if (bgTexture.empty())
|
||||
bgTexture = "FOO";
|
||||
panel->setBackground(FGTextureManager::createTexture(bgTexture.c_str()));
|
||||
|
||||
//
|
||||
// Get multibackground if any...
|
||||
//
|
||||
string mbgTexture = root->getStringValue("multibackground[0]");
|
||||
if (!mbgTexture.empty()) {
|
||||
panel->setMultiBackground(FGTextureManager::createTexture(mbgTexture.c_str()), 0);
|
||||
|
||||
mbgTexture = root->getStringValue("multibackground[1]");
|
||||
if (mbgTexture.empty())
|
||||
mbgTexture = "FOO";
|
||||
panel->setMultiBackground(FGTextureManager::createTexture(mbgTexture.c_str()), 1);
|
||||
|
||||
mbgTexture = root->getStringValue("multibackground[2]");
|
||||
if (mbgTexture.empty())
|
||||
mbgTexture = "FOO";
|
||||
panel->setMultiBackground(FGTextureManager::createTexture(mbgTexture.c_str()), 2);
|
||||
|
||||
mbgTexture = root->getStringValue("multibackground[3]");
|
||||
if (mbgTexture.empty())
|
||||
mbgTexture = "FOO";
|
||||
panel->setMultiBackground(FGTextureManager::createTexture(mbgTexture.c_str()), 3);
|
||||
|
||||
mbgTexture = root->getStringValue("multibackground[4]");
|
||||
if (mbgTexture.empty())
|
||||
mbgTexture = "FOO";
|
||||
panel->setMultiBackground(FGTextureManager::createTexture(mbgTexture.c_str()), 4);
|
||||
|
||||
mbgTexture = root->getStringValue("multibackground[5]");
|
||||
if (mbgTexture.empty())
|
||||
mbgTexture = "FOO";
|
||||
panel->setMultiBackground(FGTextureManager::createTexture(mbgTexture.c_str()), 5);
|
||||
|
||||
mbgTexture = root->getStringValue("multibackground[6]");
|
||||
if (mbgTexture.empty())
|
||||
mbgTexture = "FOO";
|
||||
panel->setMultiBackground(FGTextureManager::createTexture(mbgTexture.c_str()), 6);
|
||||
|
||||
mbgTexture = root->getStringValue("multibackground[7]");
|
||||
if (mbgTexture.empty())
|
||||
mbgTexture = "FOO";
|
||||
panel->setMultiBackground(FGTextureManager::createTexture(mbgTexture.c_str()), 7);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Create each instrument.
|
||||
//
|
||||
SG_LOG( SG_COCKPIT, SG_DEBUG, "Reading panel instruments" );
|
||||
const SGPropertyNode * instrument_group = root->getChild("instruments");
|
||||
if (instrument_group != 0) {
|
||||
int nInstruments = instrument_group->nChildren();
|
||||
for (int i = 0; i < nInstruments; i++) {
|
||||
const SGPropertyNode * node = instrument_group->getChild(i);
|
||||
if (node->getNameString() == "instrument") {
|
||||
FGPanelInstrument * instrument = readInstrument(node, path);
|
||||
if (instrument != 0)
|
||||
panel->addInstrument(instrument);
|
||||
} else if (node->getNameString() == "special-instrument") {
|
||||
//cout << "Special instrument found in instruments section!\n";
|
||||
const string name = node->getStringValue("name");
|
||||
if (name == "KLN89 GPS") {
|
||||
//cout << "Special instrument is KLN89\n";
|
||||
|
||||
int x = node->getIntValue("x", -1);
|
||||
int y = node->getIntValue("y", -1);
|
||||
int real_w = node->getIntValue("w", -1);
|
||||
int real_h = node->getIntValue("h", -1);
|
||||
// int w = node->getIntValue("w-base", -1);
|
||||
// int h = node->getIntValue("h-base", -1);
|
||||
|
||||
if (x == -1 || y == -1) {
|
||||
SG_LOG( SG_COCKPIT, SG_ALERT,
|
||||
"x and y positions must be specified and > 0" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// float w_scale = 1.0;
|
||||
// float h_scale = 1.0;
|
||||
if (real_w != -1) {
|
||||
// w_scale = float(real_w) / float(w);
|
||||
// w = real_w;
|
||||
}
|
||||
if (real_h != -1) {
|
||||
// h_scale = float(real_h) / float(h);
|
||||
// h = real_h;
|
||||
}
|
||||
|
||||
SG_LOG( SG_COCKPIT, SG_BULK, "Reading instrument " << name );
|
||||
|
||||
// Warning - hardwired size!!!
|
||||
RenderArea2D* instrument = new RenderArea2D(158, 40, 158, 40, x, y);
|
||||
KLN89* gps = (KLN89*)globals->get_subsystem("kln89");
|
||||
if (gps == NULL) {
|
||||
gps = new KLN89(instrument);
|
||||
globals->add_subsystem("kln89", gps, SGSubsystemMgr::GENERAL);
|
||||
}
|
||||
//gps->init(); // init seems to get called automagically.
|
||||
FGSpecialInstrument* gpsinst = new FGSpecialInstrument(gps);
|
||||
panel->addInstrument(gpsinst);
|
||||
} else {
|
||||
SG_LOG( SG_COCKPIT, SG_WARN, "Unknown special instrument found" );
|
||||
}
|
||||
} else {
|
||||
SG_LOG( SG_COCKPIT, SG_WARN, "Skipping " << node->getNameString()
|
||||
<< " in instruments section" );
|
||||
}
|
||||
}
|
||||
}
|
||||
SG_LOG( SG_COCKPIT, SG_BULK, "Done reading panel instruments" );
|
||||
|
||||
|
||||
//
|
||||
// Return the new panel.
|
||||
//
|
||||
return panel;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a panel from a property list.
|
||||
*
|
||||
* Each panel instrument will appear in its own, separate
|
||||
* property list. The top level simply names the panel and
|
||||
* places the instruments in their appropriate locations (and
|
||||
* optionally resizes them if necessary).
|
||||
*
|
||||
* Returns 0 if the read fails for any reason.
|
||||
*/
|
||||
FGPanel *
|
||||
fgReadPanel (istream &input)
|
||||
{
|
||||
SGPropertyNode root;
|
||||
|
||||
try {
|
||||
readProperties(input, &root);
|
||||
} catch (const sg_exception &e) {
|
||||
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::AircraftSystems,
|
||||
"Failed to load aircraft panel:" + e.getFormattedMessage());
|
||||
return 0;
|
||||
}
|
||||
return readPanel(&root, SGPath{});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a panel from a property list.
|
||||
*
|
||||
* This function opens a stream to a file, then invokes the
|
||||
* main fgReadPanel() function.
|
||||
*/
|
||||
FGPanel *
|
||||
fgReadPanel (const string &relative_path)
|
||||
{
|
||||
SGPath path = globals->resolve_aircraft_path(relative_path);
|
||||
SGPropertyNode root;
|
||||
|
||||
if (!path.exists()) {
|
||||
simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::AircraftSystems,
|
||||
"Missing panel file:" + relative_path, path);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
readProperties(path, &root);
|
||||
} catch (const sg_exception &e) {
|
||||
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::AircraftSystems,
|
||||
"Error parsing panel file:" + e.getFormattedMessage(), path);
|
||||
return 0;
|
||||
}
|
||||
return readPanel(&root, path);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// end of panel_io.cxx
|
||||
|
||||
|
||||
|
||||
38
src/Cockpit/panel_io.hxx
Normal file
38
src/Cockpit/panel_io.hxx
Normal file
@@ -0,0 +1,38 @@
|
||||
// panel_io.cxx - I/O for 2D panel.
|
||||
//
|
||||
// Written by David Megginson, started January 2000.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef __PANEL_IO_HXX
|
||||
#define __PANEL_IO_HXX
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
class FGPanel;
|
||||
|
||||
extern FGPanel * fgReadPanel (std::istream &input);
|
||||
extern FGPanel * fgReadPanel (const std::string &relative_path);
|
||||
|
||||
#endif // __PANEL_IO_HXX
|
||||
426
src/Cockpit/render_area_2d.cxx
Normal file
426
src/Cockpit/render_area_2d.cxx
Normal file
@@ -0,0 +1,426 @@
|
||||
// RenderArea2D.cxx - a class to manage 2D polygon-based drawing
|
||||
// for a complex instrument (eg. GPS).
|
||||
//
|
||||
// Written by David Luff, started 2005.
|
||||
//
|
||||
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "render_area_2d.hxx"
|
||||
|
||||
RA2DPrimitive::RA2DPrimitive() {
|
||||
invert = false;
|
||||
debug = false;
|
||||
}
|
||||
|
||||
RenderArea2D::RenderArea2D(int logx, int logy, int sizex, int sizey, int posx, int posy) {
|
||||
_logx = logx;
|
||||
_logy = logy;
|
||||
_sizex = sizex;
|
||||
_sizey = sizey;
|
||||
_posx = posx;
|
||||
_posy = posy;
|
||||
_clipx1 = 0;
|
||||
_clipx2 = _logx - 1;
|
||||
_clipy1 = 0;
|
||||
_clipy2 = _logy - 1;
|
||||
|
||||
// Default to black background / white text.
|
||||
_backgroundColor[0] = 0.0;
|
||||
_backgroundColor[1] = 0.0;
|
||||
_backgroundColor[2] = 0.0;
|
||||
_backgroundColor[3] = 1.0;
|
||||
_pixelColor[0] = 1.0;
|
||||
_pixelColor[1] = 1.0;
|
||||
_pixelColor[2] = 1.0;
|
||||
_pixelColor[3] = 1.0;
|
||||
|
||||
_ra2d_debug = false;
|
||||
}
|
||||
|
||||
void RenderArea2D::Draw(osg::State& state) {
|
||||
|
||||
static osg::ref_ptr<osg::StateSet> renderArea2DStateSet;
|
||||
if(!renderArea2DStateSet.valid()) {
|
||||
renderArea2DStateSet = new osg::StateSet;
|
||||
renderArea2DStateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF);
|
||||
renderArea2DStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
}
|
||||
|
||||
state.pushStateSet(renderArea2DStateSet.get());
|
||||
state.apply();
|
||||
state.setActiveTextureUnit(0);
|
||||
state.setClientActiveTextureUnit(0);
|
||||
|
||||
// DCL - the 2 lines below are copied verbatim from the hotspot drawing code.
|
||||
// I am not sure if they are needed here or not.
|
||||
glPushAttrib(GL_ENABLE_BIT);
|
||||
glDisable(GL_COLOR_MATERIAL);
|
||||
|
||||
// FIXME - disabling all clip planes causes bleed-through through the splash screen.
|
||||
glDisable(GL_CLIP_PLANE0);
|
||||
glDisable(GL_CLIP_PLANE1);
|
||||
glDisable(GL_CLIP_PLANE2);
|
||||
glDisable(GL_CLIP_PLANE3);
|
||||
|
||||
DoDrawBackground();
|
||||
|
||||
for(unsigned int i = 0; i < drawing_list.size(); ++i) {
|
||||
RA2DPrimitive prim = drawing_list[i];
|
||||
switch(prim.type) {
|
||||
case RA2D_LINE:
|
||||
DoDrawLine(prim.x1, prim.y1, prim.x2, prim.y2);
|
||||
break;
|
||||
case RA2D_QUAD:
|
||||
if(prim.debug) {
|
||||
//cout << "Clipping = " << _clipx1 << ", " << _clipy1 << " to " << _clipx2 << ", " << _clipy2 << '\n';
|
||||
//cout << "Drawing quad " << prim.x1 << ", " << prim.y1 << " to " << prim.x2 << ", " << prim.y2 << '\n';
|
||||
}
|
||||
DoDrawQuad(prim.x1, prim.y1, prim.x2, prim.y2, prim.invert);
|
||||
break;
|
||||
case RA2D_PIXEL:
|
||||
DoDrawPixel(prim.x1, prim.y1, prim.invert);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
drawing_list.clear();
|
||||
|
||||
glPopAttrib();
|
||||
|
||||
state.popStateSet();
|
||||
state.apply();
|
||||
state.setActiveTextureUnit(0);
|
||||
state.setClientActiveTextureUnit(0);
|
||||
}
|
||||
|
||||
void RenderArea2D::Flush() {
|
||||
drawing_list.clear();
|
||||
}
|
||||
|
||||
void RenderArea2D::SetPixelColor(const float* rgba) {
|
||||
_pixelColor[0] = rgba[0];
|
||||
_pixelColor[1] = rgba[1];
|
||||
_pixelColor[2] = rgba[2];
|
||||
_pixelColor[3] = rgba[3];
|
||||
}
|
||||
|
||||
// Set clipping region in logical units
|
||||
void RenderArea2D::SetClipRegion(int x1, int y1, int x2, int y2) {
|
||||
_clipx1 = x1;
|
||||
_clipx2 = x2;
|
||||
_clipy1 = y1;
|
||||
_clipy2 = y2;
|
||||
//cout << "Set clip region, clip region = " << _clipx1 << ", " << _clipy1 << " to " << _clipx2 << ", " << _clipy2 << '\n';
|
||||
}
|
||||
|
||||
// Set clip region to be the same as the rendered area (default)
|
||||
void RenderArea2D::ResetClipRegion() {
|
||||
_clipx1 = 0;
|
||||
_clipx2 = _logx - 1;
|
||||
_clipy1 = 0;
|
||||
_clipy2 = _logy - 1;
|
||||
//cout << "Reset clip region, clip region = " << _clipx1 << ", " << _clipy1 << " to " << _clipx2 << ", " << _clipy2 << '\n';
|
||||
}
|
||||
|
||||
void RenderArea2D::SetPosition(int posx, int posy) {
|
||||
_posx = posx;
|
||||
_posy = posy;
|
||||
}
|
||||
|
||||
void RenderArea2D::SetLogicalSize(int logx, int logy) {
|
||||
_logx = logx;
|
||||
_logy = logy;
|
||||
}
|
||||
|
||||
void RenderArea2D::SetActualSize(int sizex, int sizey) {
|
||||
_sizex = sizex;
|
||||
_sizey = sizey;
|
||||
}
|
||||
|
||||
void RenderArea2D::DrawPixel(int x, int y, bool invert) {
|
||||
// Clip
|
||||
if(x < _clipx1 || x > _clipx2 || y < _clipy1 || y > _clipy2) return;
|
||||
|
||||
RA2DPrimitive prim;
|
||||
prim.x1 = x;
|
||||
prim.y1 = y;
|
||||
prim.x2 = 0;
|
||||
prim.y2 = 0;
|
||||
prim.type = RA2D_PIXEL;
|
||||
prim.invert = invert;
|
||||
drawing_list.push_back(prim);
|
||||
}
|
||||
|
||||
void RenderArea2D::DoDrawPixel(int x, int y, bool invert) {
|
||||
// Clip. In theory this shouldn't be necessary, since all input is clipped before adding
|
||||
// to the drawing list, but it ensures that any errors in clipping lines etc will only
|
||||
// spill over the clip area within the instrument, and still be clipped from straying
|
||||
// outside the instrument.
|
||||
if(x < _clipx1 || x > _clipx2 || y < _clipy1 || y > _clipy2) return;
|
||||
|
||||
// Scale to position within background
|
||||
float fx1 = (float)x, fy1 = (float)y;
|
||||
float rx = (float)_sizex / (float)_logx;
|
||||
float ry = (float)_sizey / (float)_logy;
|
||||
fx1 *= rx;
|
||||
fy1 *= ry;
|
||||
float fx2 = fx1 + rx;
|
||||
float fy2 = fy1 + ry;
|
||||
|
||||
// Translate to final position
|
||||
fx1 += (float)_posx;
|
||||
fx2 += (float)_posx;
|
||||
fy1 += (float)_posy;
|
||||
fy2 += (float)_posy;
|
||||
|
||||
//cout << "DP: " << fx1 << ", " << fy1 << " ... " << fx2 << ", " << fy2 << '\n';
|
||||
|
||||
SetRenderColor(invert ? _backgroundColor : _pixelColor);
|
||||
SGVec2f corners[4] = {
|
||||
SGVec2f(fx1, fy1),
|
||||
SGVec2f(fx2, fy1),
|
||||
SGVec2f(fx2, fy2),
|
||||
SGVec2f(fx1, fy2)
|
||||
};
|
||||
RenderQuad(corners);
|
||||
}
|
||||
|
||||
void RenderArea2D::DrawLine(int x1, int y1, int x2, int y2) {
|
||||
// We need to clip the line to the current region before storing it in the drawing
|
||||
// list, since when we come to actually draw it the clip region may have changed.
|
||||
|
||||
// Liang-Barsky clipping algorithm
|
||||
int p[4], q[4];
|
||||
float u1 = 0.0f, u2 = 1.0f;
|
||||
p[0] = -(x2 - x1); q[0] = (x1 - _clipx1);
|
||||
p[1] = (x2 - x1); q[1] = (_clipx2 - x1);
|
||||
p[2] = -(y2 - y1); q[2] = (y1 - _clipy1);
|
||||
p[3] = (y2 - y1); q[3] = (_clipy2 - y1);
|
||||
|
||||
for(int i=0; i<4; ++i) {
|
||||
if(p[i] == 0) {
|
||||
if(q[i] < 0) {
|
||||
// Then we have a trivial rejection of a line parallel to a clip plane
|
||||
// completely outside the clip region.
|
||||
return;
|
||||
}
|
||||
} else if(p[i] < 0) {
|
||||
float r = (float)q[i]/(float)p[i];
|
||||
u1 = (u1 > r ? u1 : r);
|
||||
} else { // p[i] > 0
|
||||
float r = (float)q[i]/(float)p[i];
|
||||
u2 = (u2 < r ? u2 : r);
|
||||
}
|
||||
if(u1 > u2) {
|
||||
// Then the line is completely outside the clip area.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float fx1 = x1 + u1 * (float)(x2 - x1);
|
||||
float fy1 = y1 + u1 * (float)(y2 - y1);
|
||||
float fx2 = x1 + u2 * (float)(x2 - x1);
|
||||
float fy2 = y1 + u2 * (float)(y2 - y1);
|
||||
x1 = (int)(fx1 + 0.5);
|
||||
y1 = (int)(fy1 + 0.5);
|
||||
x2 = (int)(fx2 + 0.5);
|
||||
y2 = (int)(fy2 + 0.5);
|
||||
|
||||
RA2DPrimitive prim;
|
||||
prim.x1 = x1;
|
||||
prim.y1 = y1;
|
||||
prim.x2 = x2;
|
||||
prim.y2 = y2;
|
||||
prim.type = RA2D_LINE;
|
||||
prim.invert = false;
|
||||
drawing_list.push_back(prim);
|
||||
}
|
||||
|
||||
void RenderArea2D::DoDrawLine(int x1, int y1, int x2, int y2) {
|
||||
// Crude implementation of Bresenham line drawing algorithm.
|
||||
|
||||
// Our lines are non directional, so first order the points x-direction-wise to leave only 4 octants to consider.
|
||||
if(x2 < x1) {
|
||||
int tmp_x = x1;
|
||||
int tmp_y = y1;
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
x2 = tmp_x;
|
||||
y2 = tmp_y;
|
||||
}
|
||||
|
||||
bool flip_y = (y1 > y2 ? true : false);
|
||||
int dx = x2 - x1;
|
||||
int dy = (flip_y ? y1 - y2 : y2 - y1);
|
||||
if(dx > dy) {
|
||||
// push the x dir
|
||||
int y = y1;
|
||||
int yn = dx/2;
|
||||
for(int x=x1; x<=x2; ++x) {
|
||||
DoDrawPixel(x, y);
|
||||
yn += dy;
|
||||
if(yn >= dx) {
|
||||
yn -= dx;
|
||||
y = (flip_y ? y - 1 : y + 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// push the y dir
|
||||
int x = x1;
|
||||
int xn = dy/2;
|
||||
// Must be a more elegant way to roll the next two cases into one!
|
||||
if(flip_y) {
|
||||
for(int y=y1; y>=y2; --y) {
|
||||
DoDrawPixel(x, y);
|
||||
xn += dx;
|
||||
if(xn >= dy) {
|
||||
xn -= dy;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(int y=y1; y<=y2; ++y) {
|
||||
DoDrawPixel(x, y);
|
||||
xn += dx;
|
||||
if(xn >= dy) {
|
||||
xn -= dy;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderArea2D::DrawQuad(int x1, int y1, int x2, int y2, bool invert) {
|
||||
// Force the input to be ordered with x1 < x2 and y1 < y2.
|
||||
if(x1 > x2) {
|
||||
int x = x2;
|
||||
x2 = x1;
|
||||
x1 = x;
|
||||
}
|
||||
if(y1 > y2) {
|
||||
int y = y2;
|
||||
y2 = y1;
|
||||
y1 = y;
|
||||
}
|
||||
|
||||
// Clip the input to the current drawing region.
|
||||
x1 = x1 < _clipx1 ? _clipx1 : x1;
|
||||
if(x1 > _clipx2) { return; }
|
||||
x2 = x2 > _clipx2 ? _clipx2 : x2;
|
||||
if(x2 < _clipx1) { return; }
|
||||
y1 = y1 < _clipy1 ? _clipy1 : y1;
|
||||
if(y1 > _clipy2) { return; }
|
||||
y2 = y2 > _clipy2 ? _clipy2 : y2;
|
||||
if(y2 < _clipy1) { return; }
|
||||
|
||||
RA2DPrimitive prim;
|
||||
prim.x1 = x1;
|
||||
prim.y1 = y1;
|
||||
prim.x2 = x2;
|
||||
prim.y2 = y2;
|
||||
prim.type = RA2D_QUAD;
|
||||
prim.invert = invert;
|
||||
if(_ra2d_debug) prim.debug = true;
|
||||
drawing_list.push_back(prim);
|
||||
}
|
||||
|
||||
void RenderArea2D::DoDrawQuad(int x1, int y1, int x2, int y2, bool invert) {
|
||||
// Scale to position within background
|
||||
float fx1 = (float)x1, fy1 = (float)y1;
|
||||
float fx2 = (float)x2, fy2 = (float)y2;
|
||||
float rx = (float)_sizex / (float)_logx;
|
||||
float ry = (float)_sizey / (float)_logy;
|
||||
fx1 *= rx;
|
||||
fy1 *= ry;
|
||||
fx2 *= rx;
|
||||
fy2 *= ry;
|
||||
|
||||
fx2 += rx;
|
||||
fy2 += ry;
|
||||
|
||||
// Translate to final position
|
||||
fx1 += (float)_posx;
|
||||
fx2 += (float)_posx;
|
||||
fy1 += (float)_posy;
|
||||
fy2 += (float)_posy;
|
||||
|
||||
//cout << "DP: " << fx1 << ", " << fy1 << " ... " << fx2 << ", " << fy2 << '\n';
|
||||
|
||||
SetRenderColor(invert ? _backgroundColor : _pixelColor);
|
||||
SGVec2f corners[4] = {
|
||||
SGVec2f(fx1, fy1),
|
||||
SGVec2f(fx2, fy1),
|
||||
SGVec2f(fx2, fy2),
|
||||
SGVec2f(fx1, fy2)
|
||||
};
|
||||
RenderQuad(corners);
|
||||
}
|
||||
|
||||
void RenderArea2D::DrawBackground() {
|
||||
// Currently a NO-OP
|
||||
}
|
||||
|
||||
void RenderArea2D::DoDrawBackground() {
|
||||
SetRenderColor(_backgroundColor);
|
||||
SGVec2f corners[4] = {
|
||||
SGVec2f(_posx, _posy),
|
||||
SGVec2f(_posx + _sizex, _posy),
|
||||
SGVec2f(_posx + _sizex, _posy + _sizey),
|
||||
SGVec2f(_posx, _posy + _sizey)
|
||||
};
|
||||
|
||||
RenderQuad(corners);
|
||||
}
|
||||
|
||||
// -----------------------------------------
|
||||
//
|
||||
// Actual drawing routines copied from Atlas
|
||||
//
|
||||
// -----------------------------------------
|
||||
|
||||
void RenderArea2D::SetRenderColor( const float *rgba ) {
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, rgba);
|
||||
glColor4fv( rgba );
|
||||
}
|
||||
|
||||
void RenderArea2D::RenderQuad( const SGVec2f *p) {
|
||||
glBegin(GL_QUADS);
|
||||
glNormal3f(0.0f, 0.0f, 0.0f);
|
||||
glVertex2fv( p[0].data() );
|
||||
glVertex2fv( p[1].data() );
|
||||
glVertex2fv( p[2].data() );
|
||||
glVertex2fv( p[3].data() );
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void RenderArea2D::RenderQuad( const SGVec2f *p, const SGVec4f *color ) {
|
||||
glBegin(GL_QUADS);
|
||||
glNormal3f(0.0f, 0.0f, 0.0f);
|
||||
glColor4fv( color[0].data() ); glVertex2fv( p[0].data() );
|
||||
glColor4fv( color[1].data() ); glVertex2fv( p[1].data() );
|
||||
glColor4fv( color[2].data() ); glVertex2fv( p[2].data() );
|
||||
glColor4fv( color[3].data() ); glVertex2fv( p[3].data() );
|
||||
glEnd();
|
||||
}
|
||||
108
src/Cockpit/render_area_2d.hxx
Normal file
108
src/Cockpit/render_area_2d.hxx
Normal file
@@ -0,0 +1,108 @@
|
||||
// RenderArea2D.hxx - a class to manage 2D polygon-based drawing
|
||||
// for a complex instrument (eg. GPS).
|
||||
//
|
||||
// Written by David Luff, started 2005.
|
||||
//
|
||||
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/State>
|
||||
#include <osg/StateSet>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
enum RA2DDrawingType {
|
||||
RA2D_LINE,
|
||||
RA2D_QUAD,
|
||||
RA2D_PIXEL
|
||||
};
|
||||
|
||||
struct RA2DPrimitive {
|
||||
RA2DPrimitive();
|
||||
|
||||
RA2DDrawingType type;
|
||||
int x1, y1, x2, y2;
|
||||
bool invert;
|
||||
bool debug;
|
||||
};
|
||||
|
||||
class RenderArea2D {
|
||||
|
||||
public:
|
||||
RenderArea2D(int logx, int logy, int sizex, int sizey, int posx, int posy);
|
||||
~RenderArea2D();
|
||||
|
||||
void SetPixelColor(const float* rgba);
|
||||
void SetBackgroundColor(const float* rgba);
|
||||
void SetPosition(int posx, int posy);
|
||||
void SetLogicalSize(int logx, int logy);
|
||||
void SetActualSize(int sizex, int sizey);
|
||||
|
||||
// Set clipping region in logical units
|
||||
void SetClipRegion(int x1, int y1, int x2, int y2);
|
||||
// Set clip region to be the same as the rendered area (default)
|
||||
void ResetClipRegion();
|
||||
|
||||
// The DrawXXX functions place the shapes in the buffer, specified
|
||||
// in logical units, and clipped to the current clip region.
|
||||
void DrawPixel(int x, int y, bool invert = false);
|
||||
void DrawLine(int x1, int y1, int x2, int y2);
|
||||
void DrawQuad(int x1, int y1, int x2, int y2, bool invert = false);
|
||||
void DrawBackground();
|
||||
|
||||
// Call Draw to have the buffer contents drawn and then cleared.
|
||||
void Draw(osg::State& state);
|
||||
|
||||
// Clear the buffer contents
|
||||
void Flush();
|
||||
|
||||
// Turn debugging on or off.
|
||||
inline void SetDebugging(bool b) { _ra2d_debug = b; }
|
||||
|
||||
private:
|
||||
int _logx, _logy; // logical size of rendered area
|
||||
int _sizex, _sizey; // Actual size of rendered area
|
||||
int _posx, _posy; // Position of rendered area
|
||||
int _clipx1, _clipx2, _clipy1, _clipy2; // Current clipping region in *logical* units
|
||||
|
||||
float _backgroundColor[4];
|
||||
float _pixelColor[4];
|
||||
|
||||
// Drawing specified in logical units
|
||||
void DoDrawPixel(int x, int y, bool invert = false);
|
||||
void DoDrawLine(int x1, int y1, int x2, int y2);
|
||||
void DoDrawQuad(int x1, int y1, int x2, int y2, bool invert = false);
|
||||
void DoDrawBackground();
|
||||
|
||||
// Actual rendering routines copied from Atlas
|
||||
void SetRenderColor( const float *rgb );
|
||||
void RenderQuad( const SGVec2f *p);
|
||||
void RenderQuad( const SGVec2f *p, const SGVec4f *color );
|
||||
|
||||
std::vector<RA2DPrimitive> drawing_list;
|
||||
|
||||
// Control whether to output debugging output
|
||||
bool _ra2d_debug;
|
||||
};
|
||||
1127
src/Cockpit/wxradar.cxx
Normal file
1127
src/Cockpit/wxradar.cxx
Normal file
File diff suppressed because it is too large
Load Diff
208
src/Cockpit/wxradar.hxx
Normal file
208
src/Cockpit/wxradar.hxx
Normal file
@@ -0,0 +1,208 @@
|
||||
// Wx Radar background texture
|
||||
//
|
||||
// Written by Harald JOHNSEN, started May 2005.
|
||||
// With major amendments by Vivian MEAZZA May 2007
|
||||
// Ported to OSG by Tim MOORE Jun 2007
|
||||
//
|
||||
// Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program 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
|
||||
// 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.
|
||||
|
||||
#ifndef _INST_WXRADAR_HXX
|
||||
#define _INST_WXRADAR_HXX
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Texture2D>
|
||||
#include <osgText/Text>
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class FGODGauge;
|
||||
|
||||
class wxRadarBg : public SGSubsystem,
|
||||
public SGPropertyChangeListener
|
||||
{
|
||||
public:
|
||||
wxRadarBg(SGPropertyNode *node);
|
||||
wxRadarBg();
|
||||
virtual ~wxRadarBg();
|
||||
|
||||
// Subsystem API.
|
||||
void init() override;
|
||||
void shutdown() override;
|
||||
void update(double dt) override;
|
||||
|
||||
// Subsystem identification.
|
||||
static const char* staticSubsystemClassId() { return "radar"; }
|
||||
|
||||
virtual void valueChanged(SGPropertyNode *);
|
||||
|
||||
protected:
|
||||
std::string _name;
|
||||
int _num;
|
||||
double _time;
|
||||
double _interval;
|
||||
double _elapsed_time;
|
||||
double _persistance;
|
||||
|
||||
SGPropertyNode_ptr _serviceable_node;
|
||||
SGPropertyNode_ptr _sceneryLoaded;
|
||||
SGPropertyNode_ptr _Instrument;
|
||||
SGPropertyNode_ptr _radar_mode_control_node;
|
||||
|
||||
SGPropertyNode_ptr _user_lat_node;
|
||||
SGPropertyNode_ptr _user_lon_node;
|
||||
SGPropertyNode_ptr _user_heading_node;
|
||||
SGPropertyNode_ptr _user_alt_node;
|
||||
|
||||
FGODGauge *_odg;
|
||||
|
||||
typedef struct {
|
||||
double bearing;
|
||||
double range;
|
||||
double elevation;
|
||||
double bumpiness;
|
||||
double elapsed_time;
|
||||
} ground_echo;
|
||||
|
||||
typedef std::vector <ground_echo*> ground_echo_vector_type;
|
||||
typedef ground_echo_vector_type::iterator ground_echo_vector_iterator;
|
||||
|
||||
ground_echo_vector_type ground_echoes;
|
||||
ground_echo_vector_iterator ground_echoes_iterator;
|
||||
|
||||
// Convenience function for creating a property node with a
|
||||
// default value
|
||||
template<typename DefaultType>
|
||||
SGPropertyNode *getInstrumentNode(const char *name, DefaultType value);
|
||||
|
||||
private:
|
||||
std::string _texture_path;
|
||||
|
||||
typedef enum { ARC, MAP, PLAN, ROSE, BSCAN} DisplayMode;
|
||||
DisplayMode _display_mode;
|
||||
|
||||
float _range_nm;
|
||||
float _scale; // factor to convert nm to display units
|
||||
float _angle_offset;
|
||||
float _view_heading;
|
||||
float _x_offset, _y_offset;
|
||||
|
||||
double _radar_ref_rng;
|
||||
double _lat, _lon;
|
||||
double _antenna_ht;
|
||||
|
||||
SGPropertyNode_ptr _Tacan;
|
||||
SGPropertyNode_ptr _Radar_controls;
|
||||
|
||||
SGPropertyNode_ptr _user_speed_east_fps_node;
|
||||
SGPropertyNode_ptr _user_speed_north_fps_node;
|
||||
|
||||
SGPropertyNode_ptr _tacan_serviceable_node;
|
||||
SGPropertyNode_ptr _tacan_distance_node;
|
||||
SGPropertyNode_ptr _tacan_name_node;
|
||||
SGPropertyNode_ptr _tacan_bearing_node;
|
||||
SGPropertyNode_ptr _tacan_in_range_node;
|
||||
|
||||
SGPropertyNode_ptr _radar_weather_node;
|
||||
SGPropertyNode_ptr _radar_position_node;
|
||||
SGPropertyNode_ptr _radar_data_node;
|
||||
SGPropertyNode_ptr _radar_symbol_node;
|
||||
|
||||
SGPropertyNode_ptr _radar_centre_node;
|
||||
SGPropertyNode_ptr _radar_coverage_node;
|
||||
SGPropertyNode_ptr _radar_ref_rng_node;
|
||||
SGPropertyNode_ptr _radar_hdg_marker_node;
|
||||
SGPropertyNode_ptr _radar_rotate_node;
|
||||
SGPropertyNode_ptr _radar_tcas_node;
|
||||
SGPropertyNode_ptr _radar_absalt_node;
|
||||
|
||||
SGPropertyNode_ptr _font_node;
|
||||
SGPropertyNode_ptr _ai_enabled_node;
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> _resultTexture;
|
||||
osg::ref_ptr<osg::Texture2D> _wxEcho;
|
||||
osg::ref_ptr<osg::Geode> _radarGeode;
|
||||
osg::ref_ptr<osg::Geode> _textGeode;
|
||||
osg::Geometry *_geom;
|
||||
osg::Vec2Array *_vertices;
|
||||
osg::Vec2Array *_texCoords;
|
||||
osg::Matrixf _centerTrans;
|
||||
osg::ref_ptr<osgText::Font> _font;
|
||||
osg::Vec4 _font_color;
|
||||
osg::Vec4 _tcas_colors[4];
|
||||
float _font_size;
|
||||
float _font_spacing;
|
||||
|
||||
// FIXME: implementation of radar echoes missing
|
||||
// list_of_SGWxRadarEcho _radarEchoBuffer;
|
||||
|
||||
void update_weather();
|
||||
void update_aircraft();
|
||||
void update_tacan();
|
||||
void update_heading_marker();
|
||||
void update_data(const SGPropertyNode *ac, double alt, double heading,
|
||||
double radius, double bearing, bool selected);
|
||||
bool update_tcas(const SGPropertyNode *model,double range,double user_alt,double alt,
|
||||
double bearing,double radius, bool absMode);
|
||||
void center_map();
|
||||
void apply_map_offset();
|
||||
void updateFont();
|
||||
void calcRangeBearing(double lat, double lon, double lat2, double lon2,
|
||||
double &range, double &bearing) const;
|
||||
|
||||
bool withinRadarHorizon(double user_alt, double alt, double range);
|
||||
bool inRadarRange(double sigma, double range);
|
||||
|
||||
float calcRelBearing(float bearing, float heading);
|
||||
float calcRelBearingDeg(float bearing, float heading);
|
||||
};
|
||||
|
||||
|
||||
template<> inline
|
||||
SGPropertyNode *wxRadarBg::getInstrumentNode(const char *name, bool value)
|
||||
{
|
||||
SGPropertyNode *result = _Instrument->getNode(name, true);
|
||||
if (!result->hasValue())
|
||||
result->setBoolValue(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<> inline
|
||||
SGPropertyNode *wxRadarBg::getInstrumentNode(const char *name, double value)
|
||||
{
|
||||
SGPropertyNode *result = _Instrument->getNode(name, true);
|
||||
if (!result->hasValue())
|
||||
result->setDoubleValue(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<> inline
|
||||
SGPropertyNode *wxRadarBg::getInstrumentNode(const char *name, const char *value)
|
||||
{
|
||||
SGPropertyNode *result = _Instrument->getNode(name, true);
|
||||
if (result->hasValue())
|
||||
result->setStringValue(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // _INST_WXRADAR_HXX
|
||||
Reference in New Issue
Block a user