+/**
+ * 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_INFO,
+ "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 (!strcmp(child->getName(), "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 (!strcmp(node->getName(), "chunk")) {
+ FGTextLayer::Chunk * chunk = readTextChunk(node);
+ if (chunk != 0)
+ tlayer->addChunk(chunk);
+ } else {
+ SG_LOG( SG_COCKPIT, SG_INFO, "Skipping " << node->getName()
+ << " 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 (!strcmp(child->getName(), "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;
+ }
+