]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/HUD/HUD_tape.cxx
better use unset() for unsetting ...
[flightgear.git] / src / Instrumentation / HUD / HUD_tape.cxx
1 // HUD_tape.cxx -- HUD Tape Instrument
2 //
3 // Written by Michele America, started September 1997.
4 //
5 // Copyright (C) 1997  Michele F. America  [micheleamerica#geocities:com]
6 // Copyright (C) 2006  Melchior FRANZ  [mfranz#aon:at]
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21
22 #include "HUD.hxx"
23
24
25 HUD::Tape::Tape(HUD *hud, const SGPropertyNode *n, float x, float y) :
26     Scale(hud, n, x, y),
27     _draw_tick_bottom(n->getBoolValue("tick-bottom", false)),
28     _draw_tick_top(n->getBoolValue("tick-top", false)),
29     _draw_tick_right(n->getBoolValue("tick-right", false)),
30     _draw_tick_left(n->getBoolValue("tick-left", false)),
31     _draw_cap_bottom(n->getBoolValue("cap-bottom", false)),
32     _draw_cap_top(n->getBoolValue("cap-top", false)),
33     _draw_cap_right(n->getBoolValue("cap-right", false)),
34     _draw_cap_left(n->getBoolValue("cap-left", false)),
35     _marker_offset(n->getFloatValue("marker-offset", 0.0)),
36     _label_gap(n->getFloatValue("label-gap-width", 0.0) / 2.0),
37     _pointer(n->getBoolValue("enable-pointer", true)),
38     _format(n->getStringValue("format", "%d"))
39 {
40     _half_width_units = range_to_show() / 2.0;
41
42     const char *s;
43     s = n->getStringValue("pointer-type");
44     _pointer_type = strcmp(s, "moving") ? FIXED : MOVING;    // "fixed", "moving"
45
46     s = n->getStringValue("tick-type");
47     _tick_type = strcmp(s, "bullet") ? LINE : CIRCLE;        // "bullet", "line"
48
49     s = n->getStringValue("tick-length");                    // "variable", "constant"
50     _tick_length = strcmp(s, "constant") ? VARIABLE : CONSTANT;
51
52     _label_fmt = check_format(_format.c_str());
53     if (_label_fmt != INT && _label_fmt != LONG
54             && _label_fmt != FLOAT && _label_fmt != DOUBLE) {
55         SG_LOG(SG_INPUT, SG_ALERT, "HUD: invalid <format> '" << _format.c_str()
56                 << "' in <tape> '" << _name << "' (must be number format)");
57         _label_fmt = INT;
58         _format = "%d";
59     }
60
61     if (_minor_divs != 0.0f)
62         _div_ratio = int(_major_divs / _minor_divs + 0.5f);
63     else
64         _div_ratio = 0, _minor_divs = _major_divs;
65
66 //    int k; //odd or even values for ticks             // FIXME odd scale
67     _odd_type = int(floorf(_input.max() + 0.5)) & 1 ? true : false;
68 }
69
70
71 void HUD::Tape::draw(void) //  (HUD_scale * pscale)
72 {
73     if (!_input.isValid())
74         return;
75
76     float value = _input.getFloatValue();
77
78     if (option_vert())
79         draw_vertical(value);
80     else
81         draw_horizontal(value);
82 }
83
84
85 void HUD::Tape::draw_vertical(float value)
86 {
87     float vmin = 0.0, vmax = 0.0;
88     float marker_xs;
89     float marker_xe;
90     float marker_ye;
91     float text_y = 0.0;
92
93     float top = _y + _h;
94     float right = _x + _w;
95
96
97     if (!_pointer) {
98         vmin = value - _half_width_units; // width units == needle travel
99         vmax = value + _half_width_units; // or picture unit span.
100         text_y = _center_y;
101
102     } else if (_pointer_type == MOVING) {
103         vmin = _input.min();
104         vmax = _input.max();
105
106     } else { // FIXED
107         vmin = value - _half_width_units; // width units == needle travel
108         vmax = value + _half_width_units; // or picture unit span.
109         text_y = _center_y;
110     }
111
112     // Bottom tick bar
113     if (_draw_tick_bottom)
114         draw_line(_x, _y, right, _y);
115
116     // Top tick bar
117     if (_draw_tick_top)
118         draw_line(_x, top, right, top);
119
120     marker_xs = _x;       // x start
121     marker_xe = right;    // x extent
122     marker_ye = top;
123
124     // We do not use else in the following so that combining the
125     // two options produces a "caged" display with double
126     // carrots. The same is done for horizontal card indicators.
127
128     // draw capping lines and pointers
129     if (option_left()) {    // Calculate x marker offset
130
131         if (_draw_cap_right)
132             draw_line(marker_xe, _y, marker_xe, marker_ye);
133
134         marker_xs = marker_xe - _w / 3.0;
135
136         // draw_line(marker_xs, _center_y, marker_xe, _center_y + _w / 6);
137         // draw_line(marker_xs, _center_y, marker_xe, _center_y - _w / 6);
138
139         if (_pointer) {
140             if (_pointer_type == MOVING) {
141                 float ycentre, ypoint, xpoint;
142                 float range, right;
143
144                 if (_input.min() >= 0.0)
145                     ycentre = _y;
146                 else if (_input.max() + _input.min() == 0.0)
147                     ycentre = _center_y;
148                 else if (_odd_type)
149                     ycentre = _y + (1.0 - _input.min()) * _h / (_input.max() - _input.min());
150                 else
151                     ycentre = _y + _input.min() * _h / (_input.max() - _input.min());
152
153                 range = _h;
154                 right = _x + _w;
155
156                 if (_odd_type)
157                     ypoint = ycentre + ((value - 1.0) * range / _val_span);
158                 else
159                     ypoint = ycentre + (value * range / _val_span);
160
161                 xpoint = right + _marker_offset;
162                 draw_line(xpoint, ycentre, xpoint, ypoint);
163                 draw_line(xpoint, ypoint, xpoint - _marker_offset, ypoint);
164                 draw_line(xpoint - _marker_offset, ypoint, xpoint - 5.0, ypoint + 5.0);
165                 draw_line(xpoint - _marker_offset, ypoint, xpoint - 5.0, ypoint - 5.0);
166
167             } else { // FIXED
168                 draw_fixed_pointer(_marker_offset + marker_xe, text_y + _w / 6,
169                         _marker_offset + marker_xs, text_y, _marker_offset + marker_xe,
170                         text_y - _w / 6);
171             }
172         }
173     } // if (option_left())
174
175
176     // draw capping lines and pointers
177     if (option_right()) {
178
179         if (_draw_cap_left)
180             draw_line(_x, _y, _x, marker_ye);
181
182         marker_xe = _x + _w / 3.0;
183         // Indicator carrot
184         // draw_line(_x, _center_y +  _w / 6, marker_xe, _center_y);
185         // draw_line(_x, _center_y -  _w / 6, marker_xe, _center_y);
186
187         if (_pointer) {
188             if (_pointer_type == MOVING) {
189                 float ycentre, ypoint, xpoint;
190                 float range;
191
192                 if (_input.min() >= 0.0)
193                     ycentre = _y;
194                 else if (_input.max() + _input.min() == 0.0)
195                     ycentre = _center_y;
196                 else if (_odd_type)
197                     ycentre = _y + (1.0 - _input.min()) * _h / (_input.max() - _input.min());
198                 else
199                     ycentre = _y + _input.min() * _h / (_input.max() - _input.min());
200
201                 range = _h;
202
203                 if (_odd_type)
204                     ypoint = ycentre + ((value - 1.0) * range / _val_span);
205                 else
206                     ypoint = ycentre + (value * range / _val_span);
207
208                 xpoint = _x - _marker_offset;
209                 draw_line(xpoint, ycentre, xpoint, ypoint);
210                 draw_line(xpoint, ypoint, xpoint + _marker_offset, ypoint);
211                 draw_line(xpoint + _marker_offset, ypoint, xpoint + 5.0, ypoint + 5.0);
212                 draw_line(xpoint + _marker_offset, ypoint, xpoint + 5.0, ypoint - 5.0);
213
214             } else { // FIXED
215                 draw_fixed_pointer(-_marker_offset + _x, text_y +  _w / 6,
216                         -_marker_offset + marker_xe, text_y, -_marker_offset + _x,
217                         text_y - _w / 6);
218             }
219         } // if (_pointer)
220     } // if (option_right())
221
222
223     // At this point marker x_start and x_end values are transposed.
224     // To keep this from confusing things they are now swapped.
225     if (option_both())
226         marker_ye = marker_xs, marker_xs = marker_xe, marker_xe = marker_ye;
227
228
229
230     // Work through from bottom to top of scale. Calculating where to put
231     // minor and major ticks.
232
233     // draw scale or tape
234     float vstart = floorf(vmin / _major_divs) * _major_divs;
235     float min_diff = _w / 6.0;    // length difference between major & minor tick
236
237     // FIXME consider oddtype
238     for (int i = 0; ; i++) {
239         float v = vstart + i * _minor_divs;
240
241         if (!_modulo)
242             if (v < _input.min())
243                 continue;
244             else if (v > _input.max())
245                 break;
246
247         float y = _y + (v - vmin) * factor();
248
249         if (y < _y + 0)
250             continue;
251         if (y > top - 0)
252             break;
253
254         if (_div_ratio && i % _div_ratio) { // minor div
255             if (option_both()) {
256                 if (_tick_type == LINE) {
257                     if (_tick_length == VARIABLE) {
258                         draw_line(_x, y, marker_xs, y);
259                         draw_line(marker_xe, y, right, y);
260                     } else {
261                         draw_line(_x, y, marker_xs, y);
262                         draw_line(marker_xe, y, right, y);
263                     }
264
265                 } else { // _tick_type == CIRCLE
266                     draw_bullet(_x, y, 3.0);
267                 }
268
269             } else if (option_left()) {
270                 if (_tick_type == LINE) {
271                     if (_tick_length == VARIABLE) {
272                         draw_line(marker_xs + min_diff, y, marker_xe, y);
273                     } else {
274                         draw_line(marker_xs, y, marker_xe, y);
275                     }
276                 } else { // _tick_type == CIRCLE
277                     draw_bullet(marker_xs + 4, y, 3.0);
278                 }
279
280             } else { // if (option_right())
281                 if (_tick_type == LINE) {
282                     if (_tick_length == VARIABLE) {
283                         draw_line(marker_xs, y, marker_xe - min_diff, y);
284                     } else {
285                         draw_line(marker_xs, y, marker_xe, y);
286                     }
287
288                 } else { // _tick_type == CIRCLE
289                     draw_bullet(marker_xe - 4, y, 3.0);
290                 }
291             } // end huds both
292
293         } else { // major div
294             if (_modulo)
295                 v = fmodf(v + _modulo, _modulo);
296
297             float x;
298             int align;
299
300             if (option_both()) {
301                 if (_tick_type == LINE) {
302                     draw_line(_x, y, marker_xs, y);
303                     draw_line(marker_xs, y, right, y);
304
305                 } else { // _tick_type == CIRCLE
306                     draw_bullet(_x, y, 5.0);
307                 }
308
309                 x = marker_xs, align = CENTER;
310
311             } else {
312                 if (_tick_type == LINE)
313                     draw_line(marker_xs, y, marker_xe, y);
314                 else // _tick_type == CIRCLE
315                     draw_bullet(marker_xs + 4, y, 5.0);
316
317                 if (option_left())
318                     x = marker_xs, align = RIGHT|VCENTER;
319                 else
320                     x = marker_xe, align = LEFT|VCENTER;
321             }
322
323             if (!option_notext()) {
324                 char *s = format_value(v);
325
326                 float l, r, b, t;
327                 _hud->_text_list.align(s, align, &x, &y, &l, &r, &b, &t);
328
329                 if (b < _y || t > top)
330                     continue;
331
332                 if (_label_gap == 0.0
333                         || b < _center_y - _label_gap && t < _center_y - _label_gap
334                         || b > _center_y + _label_gap && t > _center_y + _label_gap) {
335                     draw_text(x, y, s);
336                 }
337             }
338         }
339     } // for
340 }
341
342
343 void HUD::Tape::draw_horizontal(float value)
344 {
345     float vmin = 0.0, vmax = 0.0;
346     float marker_xs;
347     float marker_xe;
348     float marker_ys;
349     float marker_ye;
350     float text_y = 0.0;
351
352     float top = _y + _h;
353     float right = _x + _w;
354
355
356     if (!_pointer) {
357         vmin = value - _half_width_units; // width units == needle travel
358         vmax = value + _half_width_units; // or picture unit span.
359         text_y = _center_y;
360
361     } else if (_pointer_type == MOVING) {
362         vmin = _input.min();
363         vmax = _input.max();
364
365     } else { // FIXED
366         vmin = value - _half_width_units; // width units == needle travel
367         vmax = value + _half_width_units; // or picture unit span.
368         text_y = _center_y;
369     }
370
371     // left tick bar
372     if (_draw_tick_left)
373         draw_line(_x, _y, _x, top);
374
375     // right tick bar
376     if (_draw_tick_right)
377         draw_line(right, _y, right, top);
378
379     marker_ys = _y;    // Starting point for
380     marker_ye = top;           // tick y location calcs
381     marker_xe = right;
382     marker_xs = _x + ((value - vmin) * factor());
383
384     if (option_top()) {
385         if (_draw_cap_bottom)
386             draw_line(_x, _y, right, _y);
387
388         // Tick point adjust
389         marker_ye  = _y + _h / 2;
390         // Bottom arrow
391         // draw_line(_center_x, marker_ye, _center_x - _h / 4, _y);
392         // draw_line(_center_x, marker_ye, _center_x + _h / 4, _y);
393         // draw pointer
394         if (_pointer) {
395             if (_pointer_type == MOVING) {
396                 float xcentre = _center_x;
397                 float range = _w;
398                 float xpoint = xcentre + (value * range / _val_span);
399                 float ypoint = _y - _marker_offset;
400                 draw_line(xcentre, ypoint, xpoint, ypoint);
401                 draw_line(xpoint, ypoint, xpoint, ypoint + _marker_offset);
402                 draw_line(xpoint, ypoint + _marker_offset, xpoint + 5.0, ypoint + 5.0);
403                 draw_line(xpoint, ypoint + _marker_offset, xpoint - 5.0, ypoint + 5.0);
404
405             } else { // FIXED
406                 draw_fixed_pointer(marker_xs - _h / 4, _y, marker_xs,
407                         marker_ye, marker_xs + _h / 4, _y);
408             }
409         }
410     } // if (option_top())
411
412     if (option_bottom()) {
413         if (_draw_cap_top)
414             draw_line(_x, top, right, top);
415
416         // Tick point adjust
417         marker_ys = top - _h / 2;
418         // Top arrow
419         // draw_line(_center_x + _h / 4, _y + _h, _center_x, marker_ys);
420         // draw_line(_center_x - _h / 4, _y + _h, _center_x , marker_ys);
421
422         if (_pointer) {
423             if (_pointer_type == MOVING) {
424                 float xcentre = _center_x;
425                 float range = _w;
426                 float hgt = _y + _h;
427                 float xpoint = xcentre + (value * range / _val_span);
428                 float ypoint = hgt + _marker_offset;
429                 draw_line(xcentre, ypoint, xpoint, ypoint);
430                 draw_line(xpoint, ypoint, xpoint, ypoint - _marker_offset);
431                 draw_line(xpoint, ypoint - _marker_offset, xpoint + 5.0, ypoint - 5.0);
432                 draw_line(xpoint, ypoint - _marker_offset, xpoint - 5.0, ypoint - 5.0);
433
434             } else { // FIXED
435                 draw_fixed_pointer(marker_xs + _h / 4, top, marker_xs, marker_ys,
436                         marker_xs - _h / 4, top);
437             }
438         }
439     } // if (option_bottom())
440
441
442     float vstart = floorf(vmin / _major_divs) * _major_divs;
443     float min_diff = _h / 6.0;    // length difference between major & minor tick
444
445     // FIXME consider oddtype
446     for (int i = 0; ; i++) {
447         float v = vstart + i * _minor_divs;
448
449         if (!_modulo)
450             if (v < _input.min())
451                 continue;
452             else if (v > _input.max())
453                 break;
454
455         float x = _x + (v - vmin) * factor();
456
457         if (x < _x + 0)
458             continue;
459         if (x > right - 0)
460             break;
461
462         if (_div_ratio && i % _div_ratio) { // minor div
463             if (option_both()) {
464                 if (_tick_length == VARIABLE) {
465                     draw_line(x, _y, x, marker_ys - 4);
466                     draw_line(x, marker_ye + 4, x, top);
467                 } else {
468                     draw_line(x, _y, x, marker_ys);
469                     draw_line(x, marker_ye, x, top);
470                 }
471
472             } else {
473                 if (option_top()) {
474                     // draw minor ticks
475                     if (_tick_length == VARIABLE)
476                         draw_line(x, marker_ys, x, marker_ye - min_diff);
477                     else
478                         draw_line(x, marker_ys, x, marker_ye);
479
480                 } else if (_tick_length == VARIABLE) {
481                     draw_line(x, marker_ys + 4, x, marker_ye);
482                 } else {
483                     draw_line(x, marker_ys, x, marker_ye);
484                 }
485             }
486
487         } else { // major divs
488             if (_modulo)
489                 v = fmodf(v + _modulo, _modulo);
490
491             float y;
492             int align;
493
494             if (option_both()) {
495                 draw_line(x, _y, x, marker_ye);
496                 draw_line(x, marker_ye, x, _y + _h);
497                 y = marker_ys, align = CENTER;
498
499             } else {
500                 draw_line(x, marker_ys, x, marker_ye);
501
502                 if (option_top())
503                     y = top, align = TOP|HCENTER;
504                 else
505                     y = _y, align = BOTTOM|HCENTER;
506             }
507
508             if (!option_notext()) {
509                 char *s = format_value(v);
510
511                 float l, r, b, t;
512                 _hud->_text_list.align(s, align, &x, &y, &l, &r, &b, &t);
513
514                 if (l < _x || r > right)
515                     continue;
516
517                 if (_label_gap == 0.0
518                         || l < _center_x - _label_gap && r < _center_x - _label_gap
519                         || l > _center_x + _label_gap && r > _center_x + _label_gap) {
520                     draw_text(x, y, s);
521                 }
522             }
523         }
524     } // for
525 }
526
527
528 char *HUD::Tape::format_value(float v)
529 {
530     if (fabsf(v) < 1e-8)   // avoid -0.0
531         v = 0.0f;
532
533     if (_label_fmt == INT)
534         snprintf(_buf, BUFSIZE, _format.c_str(), int(v + 0.5f));
535     else if (_label_fmt == LONG)
536         snprintf(_buf, BUFSIZE, _format.c_str(), long(v + 0.5f));
537     else if (_label_fmt == FLOAT)
538         snprintf(_buf, BUFSIZE, _format.c_str(), v);
539     else // _label_fmt == DOUBLE
540         snprintf(_buf, BUFSIZE, _format.c_str(), double(v));
541     return _buf;
542 }
543
544
545 void HUD::Tape::draw_fixed_pointer(float x1, float y1, float x2, float y2, float x3, float y3)
546 {
547     glBegin(GL_LINE_STRIP);
548     glVertex2f(x1, y1);
549     glVertex2f(x2, y2);
550     glVertex2f(x3, y3);
551     glEnd();
552 }
553
554