1 // HUD_tape.cxx -- HUD Tape Instrument
3 // Written by Michele America, started September 1997.
5 // Copyright (C) 1997 Michele F. America [micheleamerica#geocities:com]
6 // Copyright (C) 2006 Melchior FRANZ [mfranz#aon:at]
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.
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.
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.
23 #include "HUD_private.hxx"
25 static const float TICK_OFFSET = 2.f;
28 HUD::Tape::Tape(HUD *hud, const SGPropertyNode *n, float x, float y) :
30 _draw_tick_bottom(n->getBoolValue("tick-bottom", false)),
31 _draw_tick_top(n->getBoolValue("tick-top", false)),
32 _draw_tick_right(n->getBoolValue("tick-right", false)),
33 _draw_tick_left(n->getBoolValue("tick-left", false)),
34 _draw_cap_bottom(n->getBoolValue("cap-bottom", false)),
35 _draw_cap_top(n->getBoolValue("cap-top", false)),
36 _draw_cap_right(n->getBoolValue("cap-right", false)),
37 _draw_cap_left(n->getBoolValue("cap-left", false)),
38 _marker_offset(n->getFloatValue("marker-offset")),
39 _label_offset(n->getFloatValue("label-offset", 3.0)),
40 _label_gap(n->getFloatValue("label-gap-width") / 2.0),
41 _pointer(n->getBoolValue("enable-pointer", true)),
42 _format(n->getStringValue("format", "%d"))
44 _half_width_units = range_to_show() / 2.0;
47 s = n->getStringValue("pointer-type");
48 _pointer_type = strcmp(s, "moving") ? FIXED : MOVING; // "fixed", "moving"
50 s = n->getStringValue("tick-type");
51 _tick_type = strcmp(s, "bullet") ? LINE : CIRCLE; // "bullet", "line"
53 s = n->getStringValue("tick-length"); // "variable", "constant"
54 _tick_length = strcmp(s, "constant") ? VARIABLE : CONSTANT;
56 _label_fmt = check_format(_format.c_str());
57 if (_label_fmt != INT && _label_fmt != LONG
58 && _label_fmt != FLOAT && _label_fmt != DOUBLE) {
59 SG_LOG(SG_INPUT, SG_ALERT, "HUD: invalid <format> '" << _format.c_str()
60 << "' in <tape> '" << _name << "' (must be number format)");
65 if (_minor_divs != 0.0f)
66 _div_ratio = int(_major_divs / _minor_divs + 0.5f);
68 _div_ratio = 0, _minor_divs = _major_divs;
70 // int k; //odd or even values for ticks // FIXME odd scale
72 if (_input.max() + .5f < float(SGLimits<long>::max()))
73 _odd_type = long(floorf(_input.max() + 0.5f)) & 1 ? true : false;
77 void HUD::Tape::draw(void) // (HUD_scale * pscale)
79 if (!_input.isValid())
82 float value = _input.getFloatValue();
87 draw_horizontal(value);
91 void HUD::Tape::draw_vertical(float value)
93 float vmin = 0.0;//, vmax = 0.0;
100 float right = _x + _w;
104 vmin = value - _half_width_units; // width units == needle travel
105 // vmax = value + _half_width_units; // or picture unit span.
108 } else if (_pointer_type == MOVING) {
110 // vmax = _input.max();
113 vmin = value - _half_width_units; // width units == needle travel
114 // vmax = value + _half_width_units; // or picture unit span.
119 if (_draw_tick_bottom)
120 draw_line(_x, _y, right, _y);
124 draw_line(_x, top, right, top);
126 marker_xs = _x; // x start
127 marker_xe = right; // x extent
130 // We do not use else in the following so that combining the
131 // two options produces a "caged" display with double
132 // carrots. The same is done for horizontal card indicators.
134 // draw capping lines and pointers
135 if (option_left()) { // Calculate x marker offset
138 draw_line(marker_xe, _y, marker_xe, marker_ye);
140 marker_xs = marker_xe - _w / 3.0;
142 // draw_line(marker_xs, _center_y, marker_xe, _center_y + _w / 6);
143 // draw_line(marker_xs, _center_y, marker_xe, _center_y - _w / 6);
146 if (_pointer_type == MOVING) {
147 float ycentre, ypoint, xpoint;
150 if (_input.min() >= 0.0)
152 else if (_input.max() + _input.min() == 0.0)
155 ycentre = _y + (1.0 - _input.min()) * _h / (_input.max() - _input.min());
157 ycentre = _y + _input.min() * _h / (_input.max() - _input.min());
163 ypoint = ycentre + ((value - 1.0) * range / _val_span);
165 ypoint = ycentre + (value * range / _val_span);
167 xpoint = right + _marker_offset;
168 draw_line(xpoint, ycentre, xpoint, ypoint);
169 draw_line(xpoint, ypoint, xpoint - _marker_offset, ypoint);
170 draw_line(xpoint - _marker_offset, ypoint, xpoint - 5.0, ypoint + 5.0);
171 draw_line(xpoint - _marker_offset, ypoint, xpoint - 5.0, ypoint - 5.0);
174 draw_fixed_pointer(_marker_offset + marker_xe, text_y + _w / 6,
175 _marker_offset + marker_xs, text_y, _marker_offset + marker_xe,
179 } // if (option_left())
182 // draw capping lines and pointers
183 if (option_right()) {
186 draw_line(_x, _y, _x, marker_ye);
188 marker_xe = _x + _w / 3.0;
190 // draw_line(_x, _center_y + _w / 6, marker_xe, _center_y);
191 // draw_line(_x, _center_y - _w / 6, marker_xe, _center_y);
194 if (_pointer_type == MOVING) {
195 float ycentre, ypoint, xpoint;
198 if (_input.min() >= 0.0)
200 else if (_input.max() + _input.min() == 0.0)
203 ycentre = _y + (1.0 - _input.min()) * _h / (_input.max() - _input.min());
205 ycentre = _y + _input.min() * _h / (_input.max() - _input.min());
210 ypoint = ycentre + ((value - 1.0) * range / _val_span);
212 ypoint = ycentre + (value * range / _val_span);
214 xpoint = _x - _marker_offset;
215 draw_line(xpoint, ycentre, xpoint, ypoint);
216 draw_line(xpoint, ypoint, xpoint + _marker_offset, ypoint);
217 draw_line(xpoint + _marker_offset, ypoint, xpoint + 5.0, ypoint + 5.0);
218 draw_line(xpoint + _marker_offset, ypoint, xpoint + 5.0, ypoint - 5.0);
221 draw_fixed_pointer(-_marker_offset + _x, text_y + _w / 6,
222 -_marker_offset + marker_xe, text_y, -_marker_offset + _x,
226 } // if (option_right())
229 // At this point marker x_start and x_end values are transposed.
230 // To keep this from confusing things they are now swapped.
232 marker_ye = marker_xs, marker_xs = marker_xe, marker_xe = marker_ye;
236 // Work through from bottom to top of scale. Calculating where to put
237 // minor and major ticks.
239 // draw scale or tape
240 float vstart = floorf(vmin / _major_divs) * _major_divs;
241 float min_diff = _w / 6.0; // length difference between major & minor tick
243 // FIXME consider oddtype
244 for (int i = 0; ; i++) {
245 float v = vstart + i * _minor_divs;
248 if (v < _input.min())
250 else if (v > _input.max())
254 float y = _y + (v - vmin) * factor();
256 if (y < _y + TICK_OFFSET)
258 if (y > top - TICK_OFFSET)
261 if (_div_ratio && i % _div_ratio) { // minor div
263 if (_tick_type == LINE) {
264 if (_tick_length == VARIABLE) {
265 draw_line(_x, y, marker_xs, y);
266 draw_line(marker_xe, y, right, y);
268 draw_line(_x, y, marker_xs, y);
269 draw_line(marker_xe, y, right, y);
272 } else { // _tick_type == CIRCLE
273 draw_bullet(_x, y, 3.0);
276 } else if (option_left()) {
277 if (_tick_type == LINE) {
278 if (_tick_length == VARIABLE) {
279 draw_line(marker_xs + min_diff, y, marker_xe, y);
281 draw_line(marker_xs, y, marker_xe, y);
283 } else { // _tick_type == CIRCLE
284 draw_bullet(marker_xs + 4, y, 3.0);
287 } else { // if (option_right())
288 if (_tick_type == LINE) {
289 if (_tick_length == VARIABLE) {
290 draw_line(marker_xs, y, marker_xe - min_diff, y);
292 draw_line(marker_xs, y, marker_xe, y);
295 } else { // _tick_type == CIRCLE
296 draw_bullet(marker_xe - 4, y, 3.0);
300 } else { // major div
302 v = fmodf(v + _modulo, _modulo);
308 if (_tick_type == LINE) {
309 draw_line(_x, y, marker_xs, y);
310 draw_line(marker_xs, y, right, y);
312 } else { // _tick_type == CIRCLE
313 draw_bullet(_x, y, 5.0);
316 x = marker_xs, align = CENTER;
319 if (_tick_type == LINE)
320 draw_line(marker_xs, y, marker_xe, y);
321 else // _tick_type == CIRCLE
322 draw_bullet(marker_xs + 4, y, 5.0);
325 x = marker_xs - _label_offset, align = RIGHT|VCENTER;
327 x = marker_xe + _label_offset, align = LEFT|VCENTER;
330 if (!option_notext()) {
331 char *s = format_value(v);
334 _hud->_text_list.align(s, align, &x, &y, &l, &r, &b, &t);
336 if (b < _y || t > top)
339 if (_label_gap == 0.0
340 || (b < _center_y - _label_gap && t < _center_y - _label_gap)
341 || (b > _center_y + _label_gap && t > _center_y + _label_gap)) {
350 void HUD::Tape::draw_horizontal(float value)
352 float vmin = 0.0;//, vmax = 0.0;
357 // float text_y = 0.0;
360 float right = _x + _w;
364 vmin = value - _half_width_units; // width units == needle travel
365 // vmax = value + _half_width_units; // or picture unit span.
366 // text_y = _center_y;
368 } else if (_pointer_type == MOVING) {
370 // vmax = _input.max();
373 vmin = value - _half_width_units; // width units == needle travel
374 // vmax = value + _half_width_units; // or picture unit span.
375 // text_y = _center_y;
380 draw_line(_x, _y, _x, top);
383 if (_draw_tick_right)
384 draw_line(right, _y, right, top);
386 marker_ys = _y; // Starting point for
387 marker_ye = top; // tick y location calcs
388 // marker_xe = right;
389 marker_xs = _x + ((value - vmin) * factor());
392 if (_draw_cap_bottom)
393 draw_line(_x, _y, right, _y);
396 marker_ye = _y + _h / 2;
398 // draw_line(_center_x, marker_ye, _center_x - _h / 4, _y);
399 // draw_line(_center_x, marker_ye, _center_x + _h / 4, _y);
402 if (_pointer_type == MOVING) {
403 float xcentre = _center_x;
405 float xpoint = xcentre + (value * range / _val_span);
406 float ypoint = _y - _marker_offset;
407 draw_line(xcentre, ypoint, xpoint, ypoint);
408 draw_line(xpoint, ypoint, xpoint, ypoint + _marker_offset);
409 draw_line(xpoint, ypoint + _marker_offset, xpoint + 5.0, ypoint + 5.0);
410 draw_line(xpoint, ypoint + _marker_offset, xpoint - 5.0, ypoint + 5.0);
413 draw_fixed_pointer(marker_xs - _h / 4, _y, marker_xs,
414 marker_ye, marker_xs + _h / 4, _y);
417 } // if (option_top())
419 if (option_bottom()) {
421 draw_line(_x, top, right, top);
424 marker_ys = top - _h / 2;
426 // draw_line(_center_x + _h / 4, _y + _h, _center_x, marker_ys);
427 // draw_line(_center_x - _h / 4, _y + _h, _center_x , marker_ys);
430 if (_pointer_type == MOVING) {
431 float xcentre = _center_x;
434 float xpoint = xcentre + (value * range / _val_span);
435 float ypoint = hgt + _marker_offset;
436 draw_line(xcentre, ypoint, xpoint, ypoint);
437 draw_line(xpoint, ypoint, xpoint, ypoint - _marker_offset);
438 draw_line(xpoint, ypoint - _marker_offset, xpoint + 5.0, ypoint - 5.0);
439 draw_line(xpoint, ypoint - _marker_offset, xpoint - 5.0, ypoint - 5.0);
442 draw_fixed_pointer(marker_xs + _h / 4, top, marker_xs, marker_ys,
443 marker_xs - _h / 4, top);
446 } // if (option_bottom())
449 float vstart = floorf(vmin / _major_divs) * _major_divs;
450 float min_diff = _h / 6.0; // length difference between major & minor tick
452 // FIXME consider oddtype
453 for (int i = 0; ; i++) {
454 float v = vstart + i * _minor_divs;
457 if (v < _input.min())
459 else if (v > _input.max())
463 float x = _x + (v - vmin) * factor();
465 if (x < _x + TICK_OFFSET)
467 if (x > right - TICK_OFFSET)
470 if (_div_ratio && i % _div_ratio) { // minor div
472 if (_tick_length == VARIABLE) {
473 draw_line(x, _y, x, marker_ys - 4);
474 draw_line(x, marker_ye + 4, x, top);
476 draw_line(x, _y, x, marker_ys);
477 draw_line(x, marker_ye, x, top);
483 if (_tick_length == VARIABLE)
484 draw_line(x, marker_ys, x, marker_ye - min_diff);
486 draw_line(x, marker_ys, x, marker_ye);
488 } else if (_tick_length == VARIABLE) {
489 draw_line(x, marker_ys + 4, x, marker_ye);
491 draw_line(x, marker_ys, x, marker_ye);
495 } else { // major divs
497 v = fmodf(v + _modulo, _modulo);
503 draw_line(x, _y, x, marker_ye);
504 draw_line(x, marker_ye, x, _y + _h);
505 y = marker_ys, align = CENTER;
508 draw_line(x, marker_ys, x, marker_ye);
511 y = top - _label_offset, align = TOP|HCENTER;
513 y = _y + _label_offset, align = BOTTOM|HCENTER;
516 if (!option_notext()) {
517 char *s = format_value(v);
520 _hud->_text_list.align(s, align, &x, &y, &l, &r, &b, &t);
522 if (l < _x || r > right)
525 if (_label_gap == 0.0
526 || (l < _center_x - _label_gap && r < _center_x - _label_gap)
527 || (l > _center_x + _label_gap && r > _center_x + _label_gap)) {
536 char *HUD::Tape::format_value(float v)
538 if (fabs(v) < 1e-8) // avoid -0.0
541 if (_label_fmt == INT)
542 snprintf(_buf, BUFSIZE, _format.c_str(), int(v));
543 else if (_label_fmt == LONG)
544 snprintf(_buf, BUFSIZE, _format.c_str(), long(v));
545 else if (_label_fmt == FLOAT)
546 snprintf(_buf, BUFSIZE, _format.c_str(), v);
547 else // _label_fmt == DOUBLE
548 snprintf(_buf, BUFSIZE, _format.c_str(), double(v));
553 void HUD::Tape::draw_fixed_pointer(float x1, float y1, float x2, float y2, float x3, float y3)
555 glBegin(GL_LINE_STRIP);