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