]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/panel.cxx
20000905 changes from David Megginson to impliment a data file configurable
[flightgear.git] / src / Cockpit / panel.cxx
1 //  panel.cxx - default, 2D single-engine prop instrument panel
2 //
3 //  Written by David Megginson, started January 2000.
4 //
5 //  This program is free software; you can redistribute it and/or
6 //  modify it under the terms of the GNU General Public License as
7 //  published by the Free Software Foundation; either version 2 of the
8 //  License, or (at your option) any later version.
9 // 
10 //  This program is distributed in the hope that it will be useful, but
11 //  WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 //  General Public License for more details.
14 // 
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 //
19 //  $Id$
20
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24
25 #ifdef HAVE_WINDOWS_H          
26 #  include <windows.h>
27 #endif
28
29 #include <string.h>
30
31 #include <plib/ssg.h>
32 #include <plib/fnt.h>
33
34 #include <simgear/debug/logstream.hxx>
35 #include <simgear/misc/fgpath.hxx>
36 #include <Main/options.hxx>
37 #include <Main/views.hxx>
38 #include <Objects/texload.h>
39
40 #include "hud.hxx"
41 #include "panel.hxx"
42
43
44 \f
45 ////////////////////////////////////////////////////////////////////////
46 // Implementation of FGTextureManager.
47 ////////////////////////////////////////////////////////////////////////
48
49 map<string,ssgTexture *> FGTextureManager::_textureMap;
50
51 ssgTexture *
52 FGTextureManager::createTexture (const string &relativePath)
53 {
54   ssgTexture * texture = _textureMap[relativePath];
55   if (texture == 0) {
56     cerr << "Texture " << relativePath << " does not yet exist" << endl;
57     FGPath tpath(current_options.get_fg_root());
58     tpath.append(relativePath);
59     texture = new ssgTexture((char *)tpath.c_str(), false, false);
60     _textureMap[relativePath] = texture;
61     if (_textureMap[relativePath] == 0) 
62       cerr << "Texture *still* doesn't exist" << endl;
63     cerr << "Created texture " << relativePath
64          << " handle=" << texture->getHandle() << endl;
65   }
66
67   return texture;
68 }
69
70
71 \f
72 ////////////////////////////////////////////////////////////////////////
73 // Implementation of FGPanel.
74 ////////////////////////////////////////////////////////////////////////
75
76 FGPanel * current_panel = NULL;
77
78 FGPanel::FGPanel (int x, int y, int w, int h)
79   : _mouseDown(false),
80     _mouseInstrument(0),
81     _x(x), _y(y), _w(w), _h(h)
82 {
83   setVisibility(current_options.get_panel_status());
84   _panel_h = (int)(h * 0.5768 + 1);
85 }
86
87 FGPanel::~FGPanel ()
88 {
89   instrument_list_type::iterator current = _instruments.begin();
90   instrument_list_type::iterator last = _instruments.end();
91   
92   for ( ; current != last; ++current) {
93     delete *current;
94     *current = 0;
95   }
96 }
97
98 void
99 FGPanel::addInstrument (FGPanelInstrument * instrument)
100 {
101   _instruments.push_back(instrument);
102 }
103
104 void
105 FGPanel::update () const
106 {
107                                 // Do nothing if the panel isn't visible.
108   if (!_visibility)
109     return;
110
111                                 // If the mouse is down, do something
112   if (_mouseDown) {
113     _mouseDelay--;
114     if (_mouseDelay < 0) {
115       _mouseInstrument->doMouseAction(_mouseButton, _mouseX, _mouseY);
116       _mouseDelay = 2;
117     }
118   }
119
120                                 // Now, draw the panel
121   glMatrixMode(GL_PROJECTION);
122   glPushMatrix();
123   glLoadIdentity();
124   gluOrtho2D(_x, _x + _w, _y, _y + _h);
125
126   glMatrixMode(GL_MODELVIEW);
127   glPushMatrix();
128   glLoadIdentity();
129
130                                 // Draw the background
131   glEnable(GL_TEXTURE_2D);
132   glDisable(GL_LIGHTING);
133   glEnable(GL_BLEND);
134   glEnable(GL_ALPHA_TEST);
135   glEnable(GL_COLOR_MATERIAL);
136   // glColor4f(1.0, 1.0, 1.0, 1.0);
137   if ( cur_light_params.sun_angle * RAD_TO_DEG < 95.0 ) {
138       glColor4fv( cur_light_params.scene_diffuse );
139   } else {
140       glColor4f(0.7, 0.2, 0.2, 1.0);
141   }
142   glBindTexture(GL_TEXTURE_2D, _bg->getHandle());
143   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
144   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
145   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
146   glBegin(GL_POLYGON);
147   glTexCoord2f(0.0, 0.0); glVertex3f(_x, _y, 0);
148   glTexCoord2f(10.0, 0.0); glVertex3f(_x + _w, _y, 0);
149   glTexCoord2f(10.0, 5.0); glVertex3f(_x + _w, _y + _panel_h, 0);
150   glTexCoord2f(0.0, 5.0); glVertex3f(_x, _y + _panel_h, 0);
151   glEnd();
152
153                                 // Draw the instruments.
154   instrument_list_type::const_iterator current = _instruments.begin();
155   instrument_list_type::const_iterator end = _instruments.end();
156
157   for ( ; current != end; current++) {
158     FGPanelInstrument * instr = *current;
159     glLoadIdentity();
160     glTranslated(instr->getXPos(), instr->getYPos(), 0);
161     instr->draw();
162   }
163
164   glMatrixMode(GL_PROJECTION);
165   glPopMatrix();
166   glMatrixMode(GL_MODELVIEW);
167   glPopMatrix();
168   ssgForceBasicState();
169   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
170 }
171
172 void
173 FGPanel::setVisibility (bool visibility)
174 {
175   _visibility = visibility;
176 }
177
178 bool
179 FGPanel::getVisibility () const
180 {
181   return _visibility;
182 }
183
184 void
185 FGPanel::setBackground (ssgTexture * texture)
186 {
187   _bg = texture;
188 }
189
190 bool
191 FGPanel::doMouseAction (int button, int updown, int x, int y)
192 {
193                                 // Note a released button and return
194   // cerr << "Doing mouse action\n";
195   if (updown == 1) {
196     _mouseDown = false;
197     _mouseInstrument = 0;
198     return true;
199   }
200
201   x = (int)(((float)x / current_view.get_winWidth()) * _w);
202   y = (int)(_h - (((float)y / current_view.get_winHeight()) * _h));
203
204   for (int i = 0; i < _instruments.size(); i++) {
205     FGPanelInstrument *inst = _instruments[i];
206     int ix = inst->getXPos();
207     int iy = inst->getYPos();
208     int iw = inst->getWidth() / 2;
209     int ih = inst->getHeight() / 2;
210     if (x >= ix - iw && x < ix + iw && y >= iy - ih && y < iy + ih) {
211 //       cout << "Do mouse action for component " << i << '\n';
212       _mouseDown = true;
213       _mouseDelay = 20;
214       _mouseInstrument = inst;
215       _mouseButton = button;
216       _mouseX = x - ix;
217       _mouseY = y - iy;
218                                 // Always do the action once.
219       _mouseInstrument->doMouseAction(_mouseButton, _mouseX, _mouseY);
220       return true;
221     }
222   }
223 //   cout << "Did not click on an instrument\n";
224   return false;
225 }
226
227
228 \f
229 ////////////////////////////////////////////////////////////////////////
230 // Implementation of FGAdjustAction.
231 ////////////////////////////////////////////////////////////////////////
232
233 FGAdjustAction::FGAdjustAction (SGValue * value, float increment, 
234                                 float min, float max, bool wrap=false)
235   : _value(value), _increment(increment), _min(min), _max(max), _wrap(wrap)
236 {
237 }
238
239 FGAdjustAction::~FGAdjustAction ()
240 {
241 }
242
243 void
244 FGAdjustAction::doAction ()
245 {
246   float val = _value->getFloatValue();
247 //   cout << "Do action; value=" << value << '\n';
248   val += _increment;
249   if (val < _min) {
250     val = (_wrap ? _max : _min);
251   } else if (val > _max) {
252     val = (_wrap ? _min : _max);
253   }
254 //   cout << "New value is " << value << '\n';
255   _value->setDoubleValue(val);
256 }
257
258
259 \f
260 ////////////////////////////////////////////////////////////////////////
261 // Implementation of FGSwapAction.
262 ////////////////////////////////////////////////////////////////////////
263
264 FGSwapAction::FGSwapAction (SGValue * value1, SGValue * value2)
265   : _value1(value1), _value2(value2)
266 {
267 }
268
269 FGSwapAction::~FGSwapAction ()
270 {
271 }
272
273 void
274 FGSwapAction::doAction ()
275 {
276   float val = _value1->getFloatValue();
277   _value1->setDoubleValue(_value2->getFloatValue());
278   _value2->setDoubleValue(val);
279 }
280
281
282 \f
283 ////////////////////////////////////////////////////////////////////////
284 // Implementation of FGToggleAction.
285 ////////////////////////////////////////////////////////////////////////
286
287 FGToggleAction::FGToggleAction (SGValue * value)
288   : _value(value)
289 {
290 }
291
292 FGToggleAction::~FGToggleAction ()
293 {
294 }
295
296 void
297 FGToggleAction::doAction ()
298 {
299   _value->setBoolValue(!(_value->getBoolValue()));
300 }
301
302
303 \f
304 ////////////////////////////////////////////////////////////////////////
305 // Implementation of FGPanelInstrument.
306 ////////////////////////////////////////////////////////////////////////
307
308
309 FGPanelInstrument::FGPanelInstrument ()
310 {
311   setPosition(0, 0);
312   setSize(0, 0);
313 }
314
315 FGPanelInstrument::FGPanelInstrument (int x, int y, int w, int h)
316 {
317   setPosition(x, y);
318   setSize(w, h);
319 }
320
321 FGPanelInstrument::~FGPanelInstrument ()
322 {
323   action_list_type::iterator it = _actions.begin();
324   action_list_type::iterator last = _actions.end();
325   for ( ; it != last; it++) {
326     delete it->action;
327   }
328 }
329
330 void
331 FGPanelInstrument::setPosition (int x, int y)
332 {
333   _x = x;
334   _y = y;
335 }
336
337 void
338 FGPanelInstrument::setSize (int w, int h)
339 {
340   _w = w;
341   _h = h;
342 }
343
344 int
345 FGPanelInstrument::getXPos () const
346 {
347   return _x;
348 }
349
350 int
351 FGPanelInstrument::getYPos () const
352 {
353   return _y;
354 }
355
356 int
357 FGPanelInstrument::getWidth () const
358 {
359   return _w;
360 }
361
362 int
363 FGPanelInstrument::getHeight () const
364 {
365   return _h;
366 }
367
368 void
369 FGPanelInstrument::addAction (int button, int x, int y, int w, int h,
370                               FGPanelAction * action)
371 {
372   FGPanelInstrument::inst_action act;
373   act.button = button;
374   act.x = x;
375   act.y = y;
376   act.w = w;
377   act.h = h;
378   act.action = action;
379   _actions.push_back(act);
380 }
381
382                                 // Coordinates relative to centre.
383 bool
384 FGPanelInstrument::doMouseAction (int button, int x, int y)
385 {
386   action_list_type::iterator it = _actions.begin();
387   action_list_type::iterator last = _actions.end();
388 //   cout << "Mouse action at " << x << ',' << y << '\n';
389   for ( ; it != last; it++) {
390 //     cout << "Trying action at " << it->x << ',' << it->y << ','
391 //       << it->w <<',' << it->h << '\n';
392     if (button == it->button &&
393         x >= it->x && x < it->x + it->w && y >= it->y && y < it->y + it->h) {
394       it->action->doAction();
395       return true;
396     }
397   }
398   return false;
399 }
400
401
402 \f
403 ////////////////////////////////////////////////////////////////////////
404 // Implementation of FGLayeredInstrument.
405 ////////////////////////////////////////////////////////////////////////
406
407 FGLayeredInstrument::FGLayeredInstrument (int x, int y, int w, int h)
408   : FGPanelInstrument(x, y, w, h)
409 {
410 }
411
412 FGLayeredInstrument::~FGLayeredInstrument ()
413 {
414   // FIXME: free layers
415 }
416
417 void
418 FGLayeredInstrument::draw ()
419 {
420   for (int i = 0; i < _layers.size(); i++) {
421     glPushMatrix();
422     glTranslatef(0.0, 0.0, (i / 100.0) + 0.1);
423     _layers[i]->draw();
424     glPopMatrix();
425   }
426 }
427
428 int
429 FGLayeredInstrument::addLayer (FGInstrumentLayer *layer)
430 {
431   int n = _layers.size();
432   if (layer->getWidth() == -1) {
433     layer->setWidth(getWidth());
434   }
435   if (layer->getHeight() == -1) {
436     layer->setHeight(getHeight());
437   }
438   _layers.push_back(layer);
439   return n;
440 }
441
442 int
443 FGLayeredInstrument::addLayer (CroppedTexture &texture,
444                                int w = -1, int h = -1)
445 {
446   return addLayer(new FGTexturedLayer(texture, w, h));
447 }
448
449 void
450 FGLayeredInstrument::addTransformation (FGInstrumentLayer::transform_type type,
451                                         const SGValue * value,
452                                         float min, float max,
453                                         float factor, float offset)
454 {
455   int layer = _layers.size() - 1;
456   _layers[layer]->addTransformation(type, value, min, max, factor, offset);
457 }
458
459 void
460 FGLayeredInstrument::addTransformation (FGInstrumentLayer::transform_type type,
461                                         float offset)
462 {
463   addTransformation(type, 0, 0.0, 0.0, 1.0, offset);
464 }
465
466
467 \f
468 ////////////////////////////////////////////////////////////////////////
469 // Implementation of FGInstrumentLayer.
470 ////////////////////////////////////////////////////////////////////////
471
472 FGInstrumentLayer::FGInstrumentLayer (int w, int h)
473   : _w(w),
474     _h(h)
475 {
476 }
477
478 FGInstrumentLayer::~FGInstrumentLayer ()
479 {
480   transformation_list::iterator it = _transformations.begin();
481   transformation_list::iterator end = _transformations.end();
482   while (it != end) {
483     delete *it;
484     it++;
485   }
486 }
487
488 void
489 FGInstrumentLayer::transform () const
490 {
491   transformation_list::const_iterator it = _transformations.begin();
492   transformation_list::const_iterator last = _transformations.end();
493   while (it != last) {
494     transformation *t = *it;
495     float val = (t->value == 0 ? 0.0 : t->value->getFloatValue());
496     if (val < t->min) {
497       val = t->min;
498     } else if (val > t->max) {
499       val = t->max;
500     }
501     val = val * t->factor + t->offset;
502
503     switch (t->type) {
504     case XSHIFT:
505       glTranslatef(val, 0.0, 0.0);
506       break;
507     case YSHIFT:
508       glTranslatef(0.0, val, 0.0);
509       break;
510     case ROTATION:
511       glRotatef(-val, 0.0, 0.0, 1.0);
512       break;
513     }
514     it++;
515   }
516 }
517
518 void
519 FGInstrumentLayer::addTransformation (transform_type type,
520                                       const SGValue * value,
521                                       float min, float max,
522                                       float factor, float offset)
523 {
524   transformation *t = new transformation;
525   t->type = type;
526   t->value = value;
527   t->min = min;
528   t->max = max;
529   t->factor = factor;
530   t->offset = offset;
531   _transformations.push_back(t);
532 }
533
534
535 \f
536 ////////////////////////////////////////////////////////////////////////
537 // Implementation of FGTexturedLayer.
538 ////////////////////////////////////////////////////////////////////////
539
540
541 FGTexturedLayer::FGTexturedLayer (CroppedTexture &texture, int w, int h)
542   : FGInstrumentLayer(w, h)
543 {
544   setTexture(texture);
545 }
546
547
548 FGTexturedLayer::~FGTexturedLayer ()
549 {
550 }
551
552
553 void
554 FGTexturedLayer::draw ()
555 {
556   int w2 = _w / 2;
557   int h2 = _h / 2;
558
559   transform();
560   glBindTexture(GL_TEXTURE_2D, _texture->texture->getHandle());
561   glBegin(GL_POLYGON);
562   if ( cur_light_params.sun_angle * RAD_TO_DEG < 95.0 ) {
563       glColor4fv( cur_light_params.scene_diffuse );
564   } else {
565       glColor4f(0.7, 0.2, 0.2, 1.0);
566   }
567   glTexCoord2f(_texture->minX, _texture->minY); glVertex2f(-w2, -h2);
568   glTexCoord2f(_texture->maxX, _texture->minY); glVertex2f(w2, -h2);
569   glTexCoord2f(_texture->maxX, _texture->maxY); glVertex2f(w2, h2);
570   glTexCoord2f(_texture->minX, _texture->maxY); glVertex2f(-w2, h2);
571   glEnd();
572 }
573
574
575 \f
576 ////////////////////////////////////////////////////////////////////////
577 // Implementation of FGTextLayer.
578 ////////////////////////////////////////////////////////////////////////
579
580 FGTextLayer::FGTextLayer (int w, int h, Chunk * chunk1, Chunk * chunk2,
581                           Chunk * chunk3)
582   : FGInstrumentLayer(w, h)
583 {
584   _color[0] = _color[1] = _color[2] = 0.0;
585   _color[3] = 1.0;
586   if (chunk1)
587     addChunk(chunk1);
588   if (chunk2)
589     addChunk(chunk2);
590   if (chunk3)
591     addChunk(chunk3);
592 }
593
594 FGTextLayer::~FGTextLayer ()
595 {
596   chunk_list::iterator it = _chunks.begin();
597   chunk_list::iterator last = _chunks.end();
598   for ( ; it != last; it++) {
599     delete *it;
600   }
601 }
602
603 void
604 FGTextLayer::draw ()
605 {
606   glPushMatrix();
607   glColor4fv(_color);
608   transform();
609   _renderer.setFont(guiFntHandle);
610   _renderer.setPointSize(14);
611   _renderer.begin();
612   _renderer.start3f(0, 0, 0);
613
614                                 // Render each of the chunks.
615   chunk_list::const_iterator it = _chunks.begin();
616   chunk_list::const_iterator last = _chunks.end();
617   for ( ; it != last; it++) {
618     _renderer.puts((*it)->getValue());
619   }
620
621   _renderer.end();
622   glColor4f(1.0, 1.0, 1.0, 1.0);        // FIXME
623   glPopMatrix();
624 }
625
626 void
627 FGTextLayer::addChunk (FGTextLayer::Chunk * chunk)
628 {
629   _chunks.push_back(chunk);
630 }
631
632 void
633 FGTextLayer::setColor (float r, float g, float b)
634 {
635   _color[0] = r;
636   _color[1] = g;
637   _color[2] = b;
638   _color[3] = 1.0;
639 }
640
641 void
642 FGTextLayer::setPointSize (const float size)
643 {
644   _renderer.setPointSize(size);
645 }
646
647 void
648 FGTextLayer::setFont(fntFont * font)
649 {
650   _renderer.setFont(font);
651 }
652
653
654 \f
655 ////////////////////////////////////////////////////////////////////////
656 // Implementation of FGTextLayer::Chunk.
657 ////////////////////////////////////////////////////////////////////////
658
659 FGTextLayer::Chunk::Chunk (char * text, char * fmt = "%s")
660   : _type(FGTextLayer::TEXT), _fmt(fmt)
661 {
662   _value._text = text;
663 }
664
665 FGTextLayer::Chunk::Chunk (ChunkType type, const SGValue * value,
666                            char * fmt = 0, float mult = 1.0)
667   : _type(type), _fmt(fmt), _mult(mult)
668 {
669   if (_fmt == 0) {
670     if (type == TEXT_VALUE)
671       _fmt = "%s";
672     else
673       _fmt = "%.2f";
674   }
675   _value._value = value;
676 }
677
678 char *
679 FGTextLayer::Chunk::getValue () const
680 {
681   switch (_type) {
682   case TEXT:
683     sprintf(_buf, _fmt, _value._text);
684     return _buf;
685   case TEXT_VALUE:
686     sprintf(_buf, _fmt, _value._value->getStringValue().c_str());
687     break;
688   case DOUBLE_VALUE:
689     sprintf(_buf, _fmt, _value._value->getFloatValue() * _mult);
690     break;
691   }
692   return _buf;
693 }
694
695
696 \f
697 ////////////////////////////////////////////////////////////////////////
698 // Implementation of FGSwitchLayer.
699 ////////////////////////////////////////////////////////////////////////
700
701 FGSwitchLayer::FGSwitchLayer (int w, int h, const SGValue * value,
702                               FGInstrumentLayer * layer1,
703                               FGInstrumentLayer * layer2)
704   : FGInstrumentLayer(w, h), _value(value), _layer1(layer1), _layer2(layer2)
705 {
706 }
707
708 FGSwitchLayer::~FGSwitchLayer ()
709 {
710   delete _layer1;
711   delete _layer2;
712 }
713
714 void
715 FGSwitchLayer::draw ()
716 {
717   transform();
718   if (_value->getBoolValue()) {
719     _layer1->draw();
720   } else {
721     _layer2->draw();
722   }
723 }
724
725 \f
726 // end of panel.cxx