+ _odg = new FGODGauge;
+ _odg->setSize(512);
+
+ _ai_enabled_node = fgGetNode("/sim/ai/enabled", true);
+
+ _user_lat_node = fgGetNode("/position/latitude-deg", true);
+ _user_lon_node = fgGetNode("/position/longitude-deg", true);
+ _user_alt_node = fgGetNode("/position/altitude-ft", true);
+
+ _user_speed_east_fps_node = fgGetNode("/velocities/speed-east-fps", true);
+ _user_speed_north_fps_node = fgGetNode("/velocities/speed-north-fps", true);
+
+ _tacan_serviceable_node = _Tacan->getNode("serviceable", true);
+ _tacan_distance_node = _Tacan->getNode("indicated-distance-nm", true);
+ _tacan_name_node = _Tacan->getNode("name", true);
+ _tacan_bearing_node = _Tacan->getNode("indicated-bearing-true-deg", true);
+ _tacan_in_range_node = _Tacan->getNode("in-range", true);
+
+ _radar_mode_control_node = _Instrument->getNode("mode-control", true);
+ _radar_coverage_node = _Instrument->getNode("limit-deg", true);
+ _radar_ref_rng_node = _Instrument->getNode("reference-range-nm", true);
+ _radar_hdg_marker_node = _Instrument->getNode("heading-marker", true);
+
+ SGPropertyNode *n = _Instrument->getNode("display-controls", true);
+ _radar_weather_node = n->getNode("WX", true);
+ _radar_position_node = n->getNode("pos", true);
+ _radar_data_node = n->getNode("data", true);
+ _radar_symbol_node = n->getNode("symbol", true);
+ _radar_centre_node = n->getNode("centre", true);
+ _radar_rotate_node = n->getNode("rotate", true);
+ _radar_tcas_node = n->getNode("tcas", true);
+ _radar_absalt_node = n->getNode("abs-altitude", true);
+
+ _radar_centre_node->setBoolValue(false);
+ if (!_radar_coverage_node->hasValue())
+ _radar_coverage_node->setFloatValue(120);
+ if (!_radar_ref_rng_node->hasValue())
+ _radar_ref_rng_node->setDoubleValue(35);
+ if (!_radar_hdg_marker_node->hasValue())
+ _radar_hdg_marker_node->setBoolValue(true);
+
+ _x_offset = 0;
+ _y_offset = 0;
+
+ // OSG geometry setup. The polygons for the radar returns will be
+ // stored in a single Geometry. The geometry will have several
+ // primitive sets so we can have different kinds of polys and
+ // choose a different overall color for each set.
+ _radarGeode = new osg::Geode;
+ osg::StateSet *stateSet = _radarGeode->getOrCreateStateSet();
+ stateSet->setTextureAttributeAndModes(0, _wxEcho.get());
+ _geom = new osg::Geometry;
+ _geom->setUseDisplayList(false);
+ // Initially allocate space for 128 quads
+ _vertices = new osg::Vec2Array;
+ _vertices->setDataVariance(osg::Object::DYNAMIC);
+ _vertices->reserve(128 * 4);
+ _geom->setVertexArray(_vertices);
+ _texCoords = new osg::Vec2Array;
+ _texCoords->setDataVariance(osg::Object::DYNAMIC);
+ _texCoords->reserve(128 * 4);
+ _geom->setTexCoordArray(0, _texCoords);
+ osg::Vec3Array *colors = new osg::Vec3Array;
+ colors->push_back(osg::Vec3(1.0f, 1.0f, 1.0f)); // color of echos
+ colors->push_back(osg::Vec3(1.0f, 0.0f, 0.0f)); // arc mask
+ colors->push_back(osg::Vec3(0.0f, 0.0f, 0.0f)); // rest of mask
+ _geom->setColorBinding(osg::Geometry::BIND_PER_PRIMITIVE_SET);
+ _geom->setColorArray(colors);
+ osg::PrimitiveSet *pset = new osg::DrawArrays(osg::PrimitiveSet::QUADS);
+ pset->setDataVariance(osg::Object::DYNAMIC);
+ _geom->addPrimitiveSet(pset);
+ pset = new osg::DrawArrays(osg::PrimitiveSet::QUADS);
+ pset->setDataVariance(osg::Object::DYNAMIC);
+ _geom->addPrimitiveSet(pset);
+ pset = new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES);
+ pset->setDataVariance(osg::Object::DYNAMIC);
+ _geom->addPrimitiveSet(pset);
+ _geom->setInitialBound(osg::BoundingBox(osg::Vec3f(-256.0f, -256.0f, 0.0f),
+ osg::Vec3f(256.0f, 256.0f, 0.0f)));
+ _radarGeode->addDrawable(_geom);
+ _odg->allocRT();
+ // Texture in the 2D panel system
+ FGTextureManager::addTexture(_texture_path.c_str(), _odg->getTexture());
+
+ _textGeode = new osg::Geode;
+
+ osg::Camera *camera = _odg->getCamera();
+ camera->addChild(_radarGeode.get());
+ camera->addChild(_textGeode.get());
+
+ updateFont();
+}
+
+
+// Local coordinates for each echo
+const osg::Vec3f echoCoords[4] = {
+ osg::Vec3f(-.7f, -.7f, 0.0f), osg::Vec3f(.7f, -.7f, 0.0f),
+ osg::Vec3f(.7f, .7f, 0.0f), osg::Vec3f(-.7f, .7f, 0.0f)
+};
+
+
+const osg::Vec2f echoTexCoords[4] = {
+ osg::Vec2f(0.0f, 0.0f), osg::Vec2f(UNIT, 0.0f),
+ osg::Vec2f(UNIT, UNIT), osg::Vec2f(0.0f, UNIT)
+};
+
+
+// helper
+static void
+addQuad(osg::Vec2Array *vertices, osg::Vec2Array *texCoords,
+ const osg::Matrixf& transform, const osg::Vec2f& texBase)
+{
+ for (int i = 0; i < 4; i++) {
+ const osg::Vec3f coords = transform.preMult(echoCoords[i]);
+ texCoords->push_back(texBase + echoTexCoords[i]);
+ vertices->push_back(osg::Vec2f(coords.x(), coords.y()));
+ }
+}
+
+
+// Rotate by a heading value
+static inline
+osg::Matrixf wxRotate(float angle)
+{
+ return osg::Matrixf::rotate(angle, 0.0f, 0.0f, -1.0f);