]> git.mxchange.org Git - flightgear.git/blob - utils/fgpanel/panel.cxx
Merge branch 'next' of gitorious.org:fg/flightgear into next
[flightgear.git] / utils / fgpanel / 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 //
19 //  $Id: panel.cxx,v 1.44 2006/09/05 20:28:48 curt Exp $
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 <stdio.h>      // sprintf
30 #include <string.h>
31
32 #include <simgear/compiler.h>
33
34 #include <GL/glut.h>
35
36 #include <plib/fnt.h>
37
38 #include <simgear/debug/logstream.hxx>
39 #include <simgear/math/SGMath.hxx>
40 #include <simgear/misc/sg_path.hxx>
41
42 #include "panel.hxx"
43 #include "ApplicationProperties.hxx"
44 ////////////////////////////////////////////////////////////////////////
45 // Local functions.
46 ////////////////////////////////////////////////////////////////////////
47
48 class FGDummyTextureLoader : public FGTextureLoaderInterface {
49 public:
50   virtual GLuint loadTexture( const string & filename );
51 };
52
53 GLuint FGDummyTextureLoader::loadTexture( const string & filename )
54 {
55   GLuint _texture = 0;
56   glGenTextures( 1, &_texture );
57   glBindTexture( GL_TEXTURE_2D, _texture );
58
59 //  glTexEnvi       ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) ;
60 //  glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) ;
61 //  glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ) ;
62 //  glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ) ;
63 //  glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ) ;
64
65   GLubyte image[ 2 * 2 * 3 ] ;
66
67   /* Red and white chequerboard */
68   image [ 0 ] = 255 ; image [ 1 ] =  0  ; image [ 2 ] =  0  ;
69   image [ 3 ] = 255 ; image [ 4 ] = 255 ; image [ 5 ] = 255 ;
70   image [ 6 ] = 255 ; image [ 7 ] = 255 ; image [ 8 ] = 255 ;
71   image [ 9 ] = 255 ; image [ 10] =  0  ; image [ 11] =  0  ;
72
73   glTexImage2D(GL_TEXTURE_2D,0, GL_RGB, 2, 2, 0,
74         GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) image);
75
76   return _texture;
77 }
78
79 ////////////////////////////////////////////////////////////////////////
80 // Implementation of FGCropped Texture.
81 ////////////////////////////////////////////////////////////////////////
82
83 GLuint FGCroppedTexture::current_bound_texture = 0;
84 map<string,GLuint> FGCroppedTexture::cache;
85 map<string,FGTextureLoaderInterface*> FGCroppedTexture::textureLoader;
86 static FGDummyTextureLoader dummyTextureLoader;
87
88 FGCroppedTexture::FGCroppedTexture (const string &path,
89                                     float minX, float minY,
90                                     float maxX, float maxY)
91   : _path(path),
92     _minX(minX), _minY(minY), _maxX(maxX), _maxY(maxY), _texture(0)
93 {
94 }
95
96 FGCroppedTexture::~FGCroppedTexture ()
97 {
98 }
99
100 void FGCroppedTexture::bind( bool doGLBind )
101 {
102   if( _texture == 0 ) {
103     SG_LOG( SG_COCKPIT, SG_DEBUG, "First bind of texture " << _path );
104     if( cache.count(_path) > 0 ) {
105       _texture = cache[_path];
106       SG_LOG( SG_COCKPIT, SG_DEBUG, "Using texture " << _path << " from cache (#" << _texture << ")" );
107     } else {
108       SGPath tpath = ApplicationProperties::GetRootPath(_path.c_str());
109       string extension = tpath.extension();
110       FGTextureLoaderInterface * loader = &dummyTextureLoader;
111       if( textureLoader.count( extension ) == 0 ) {
112         SG_LOG( SG_COCKPIT, SG_ALERT, "Can't handle textures of type " << extension );
113       } else {
114         loader = textureLoader[extension];
115       }
116
117       _texture = loader->loadTexture( tpath.c_str() );
118       SG_LOG( SG_COCKPIT, SG_DEBUG, "Texture " << tpath.c_str() << " loaded from file as #" << _texture );
119       
120       cache[_path] = _texture;
121     }
122   }
123
124   if( !doGLBind || current_bound_texture == _texture )
125     return;
126
127   glBindTexture( GL_TEXTURE_2D, _texture );
128   current_bound_texture = _texture;
129 }
130
131 \f
132 ////////////////////////////////////////////////////////////////////////
133 // Implementation of FGPanel.
134 ////////////////////////////////////////////////////////////////////////
135
136 /**
137  * Constructor.
138  */
139 FGPanel::FGPanel ( SGPropertyNode_ptr root)
140   : _root(root),
141     _flipx(root->getNode("/sim/panel/flip-x", true)),
142     _rotate(root->getNode("/sim/panel/rotate-deg", true)),
143     _bg_width(1.0), _bg_height(1.0),
144     initDisplayList(0)
145 {
146 }
147
148
149 /**
150  * Destructor.
151  */
152 FGPanel::~FGPanel ()
153 {
154   for (instrument_list_type::iterator it = _instruments.begin();
155        it != _instruments.end();
156        it++) {
157     delete *it;
158     *it = 0;
159   }
160 }
161
162
163 /**
164  * Add an instrument to the panel.
165  */
166 void
167 FGPanel::addInstrument (FGPanelInstrument * instrument)
168 {
169   _instruments.push_back(instrument);
170 }
171
172
173 /**
174  * Initialize the panel.
175  */
176 void
177 FGPanel::init ()
178 {
179 }
180
181
182 /**
183  * Bind panel properties.
184  */
185 void
186 FGPanel::bind ()
187 {
188 }
189
190
191 /**
192  * Unbind panel properties.
193  */
194 void
195 FGPanel::unbind ()
196 {
197 }
198
199 GLuint FGPanel::getInitDisplayList()
200 {
201   if( initDisplayList != 0 ) return initDisplayList;
202   glMatrixMode(GL_PROJECTION);
203   glLoadIdentity();
204   if ( _flipx->getBoolValue() ) {
205     gluOrtho2D( _width, 0, _height, 0 ); /* up side down */
206   } else {
207     gluOrtho2D( 0, _width, 0, _height ); /* right side up */
208   }
209
210   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
211   
212   glMatrixMode(GL_MODELVIEW);
213   glLoadIdentity();
214
215   glClear( GL_COLOR_BUFFER_BIT);
216
217   // save some state
218   glPushAttrib( GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT
219                 | GL_TEXTURE_BIT | GL_PIXEL_MODE_BIT | GL_CULL_FACE 
220                 | GL_DEPTH_BUFFER_BIT );
221
222   // Draw the background
223   glEnable(GL_TEXTURE_2D);
224
225   glDisable(GL_LIGHTING);
226   glEnable(GL_BLEND);
227   glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
228   glEnable(GL_ALPHA_TEST);
229   glEnable(GL_COLOR_MATERIAL);
230   glEnable(GL_CULL_FACE);
231   glCullFace(GL_BACK);
232   glDisable(GL_DEPTH_TEST);
233
234   if (_bg != NULL) {
235     _bg->bind();
236 //    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
237     glBegin(GL_QUADS);
238     glTexCoord2f(0.0, 0.0); glVertex2f(0, 0);
239     glTexCoord2f(_bg_width, 0.0); glVertex2f(_width, 0);
240     glTexCoord2f(_bg_width, _bg_height); glVertex2f(_width, _height);
241     glTexCoord2f(0.0, _bg_height); glVertex2f(0, _height);
242     glEnd();
243   } else if( _mbg[0] != NULL ) {
244     for (int i = 0; i < 4; i ++) {
245       // top row of textures...(1,3,5,7)
246       _mbg[i*2]->bind();
247 //      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
248       glBegin(GL_QUADS);
249       glTexCoord2f(0.0, 0.0); glVertex2f(i*_width/4,     _height/2);
250       glTexCoord2f(1.0, 0.0); glVertex2f((i+1)*_width/4, _height/2);
251       glTexCoord2f(1.0, 1.0); glVertex2f((i+1)*_width/4, _height);
252       glTexCoord2f(0.0, 1.0); glVertex2f(i*_width/4,     _height);
253       glEnd();
254       // bottom row of textures...(2,4,6,8)
255       _mbg[i*2+1]->bind();
256 //      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
257       glBegin(GL_QUADS);
258       glTexCoord2f(0.0, 0.0); glVertex2f( i*_width/4,     0);
259       glTexCoord2f(1.0, 0.0); glVertex2f( (i+1)*_width/4, 0);
260       glTexCoord2f(1.0, 1.0); glVertex2f( (i+1)*_width/4, _height/2);
261       glTexCoord2f(0.0, 1.0); glVertex2f( i*_width/4,     _height/2);
262       glEnd();
263     }
264   } else {
265     float c[4];
266     glGetFloatv( GL_CURRENT_COLOR, c );
267     glColor4f( 0.0, 0.0, 0.0, 1.0 );
268     glBegin(GL_QUADS);
269     glVertex2f(0, 0);
270     glVertex2f(_width, 0);
271     glVertex2f(_width, _height);
272     glVertex2f(0, _height);
273     glEnd();
274     glColor4fv( c );
275   }
276
277
278   return initDisplayList;  
279 }
280
281 void
282 FGPanel::update (double dt)
283 {
284   glCallList(getInitDisplayList());
285
286   // Draw the instruments.
287   // Syd Adams: added instrument clipping
288   instrument_list_type::const_iterator current = _instruments.begin();
289   instrument_list_type::const_iterator end = _instruments.end();
290
291   GLdouble blx[4]={1.0,0.0,0.0,0.0};
292   GLdouble bly[4]={0.0,1.0,0.0,0.0};
293   GLdouble urx[4]={-1.0,0.0,0.0,0.0};
294   GLdouble ury[4]={0.0,-1.0,0.0,0.0};
295
296   for ( ; current != end; current++) {
297     FGPanelInstrument * instr = *current;
298     glPushMatrix();
299     glTranslated(instr->getXPos(), instr->getYPos(), 0);
300
301     int ix= instr->getWidth();
302     int iy= instr->getHeight();
303     glPushMatrix();
304     glTranslated(-ix/2,-iy/2,0);
305     glClipPlane(GL_CLIP_PLANE0,blx);
306     glClipPlane(GL_CLIP_PLANE1,bly);
307     glEnable(GL_CLIP_PLANE0);
308     glEnable(GL_CLIP_PLANE1);
309
310     glTranslated(ix,iy,0);
311     glClipPlane(GL_CLIP_PLANE2,urx);
312     glClipPlane(GL_CLIP_PLANE3,ury);
313     glEnable(GL_CLIP_PLANE2);
314     glEnable(GL_CLIP_PLANE3);
315     glPopMatrix();
316     instr->draw();
317
318     glPopMatrix();
319   }
320
321   glDisable(GL_CLIP_PLANE0);
322   glDisable(GL_CLIP_PLANE1);
323   glDisable(GL_CLIP_PLANE2);
324   glDisable(GL_CLIP_PLANE3);
325
326   // restore some original state
327   glPopAttrib();
328 }
329
330 #if 0
331 /**
332  * Update the panel.
333  */
334 void
335 FGPanel::update (double dt)
336 {
337   glMatrixMode(GL_PROJECTION);
338   glLoadIdentity();
339   if ( _flipx->getBoolValue() ) {
340     gluOrtho2D( _width, 0, _height, 0 ); /* up side down */
341   } else {
342     gluOrtho2D( 0, _width, 0, _height ); /* right side up */
343   }
344
345   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
346   
347   glMatrixMode(GL_MODELVIEW);
348   glLoadIdentity();
349   
350   draw();
351 }
352
353 void FGPanel::draw()
354 {
355   glClear( GL_COLOR_BUFFER_BIT);
356
357   // save some state
358   glPushAttrib( GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT
359                 | GL_TEXTURE_BIT | GL_PIXEL_MODE_BIT | GL_CULL_FACE 
360                 | GL_DEPTH_BUFFER_BIT );
361
362   // Draw the background
363   glEnable(GL_TEXTURE_2D);
364
365   glDisable(GL_LIGHTING);
366   glEnable(GL_BLEND);
367   glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
368   glEnable(GL_ALPHA_TEST);
369   glEnable(GL_COLOR_MATERIAL);
370   glEnable(GL_CULL_FACE);
371   glCullFace(GL_BACK);
372   glDisable(GL_DEPTH_TEST);
373
374   if (_bg != NULL) {
375     _bg->bind();
376 //    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
377     glBegin(GL_QUADS);
378     glTexCoord2f(0.0, 0.0); glVertex2f(0, 0);
379     glTexCoord2f(_bg_width, 0.0); glVertex2f(_width, 0);
380     glTexCoord2f(_bg_width, _bg_height); glVertex2f(_width, _height);
381     glTexCoord2f(0.0, _bg_height); glVertex2f(0, _height);
382     glEnd();
383   } else if( _mbg[0] != NULL ) {
384     for (int i = 0; i < 4; i ++) {
385       // top row of textures...(1,3,5,7)
386       _mbg[i*2]->bind();
387 //      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
388       glBegin(GL_QUADS);
389       glTexCoord2f(0.0, 0.0); glVertex2f(i*_width/4,     _height/2);
390       glTexCoord2f(1.0, 0.0); glVertex2f((i+1)*_width/4, _height/2);
391       glTexCoord2f(1.0, 1.0); glVertex2f((i+1)*_width/4, _height);
392       glTexCoord2f(0.0, 1.0); glVertex2f(i*_width/4,     _height);
393       glEnd();
394       // bottom row of textures...(2,4,6,8)
395       _mbg[i*2+1]->bind();
396 //      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
397       glBegin(GL_QUADS);
398       glTexCoord2f(0.0, 0.0); glVertex2f( i*_width/4,     0);
399       glTexCoord2f(1.0, 0.0); glVertex2f( (i+1)*_width/4, 0);
400       glTexCoord2f(1.0, 1.0); glVertex2f( (i+1)*_width/4, _height/2);
401       glTexCoord2f(0.0, 1.0); glVertex2f( i*_width/4,     _height/2);
402       glEnd();
403     }
404   } else {
405     float c[4];
406     glGetFloatv( GL_CURRENT_COLOR, c );
407     glColor4f( 0.0, 0.0, 0.0, 1.0 );
408     glBegin(GL_QUADS);
409     glVertex2f(0, 0);
410     glVertex2f(_width, 0);
411     glVertex2f(_width, _height);
412     glVertex2f(0, _height);
413     glEnd();
414     glColor4fv( c );
415   }
416
417   // Draw the instruments.
418   // Syd Adams: added instrument clipping
419   instrument_list_type::const_iterator current = _instruments.begin();
420   instrument_list_type::const_iterator end = _instruments.end();
421
422   GLdouble blx[4]={1.0,0.0,0.0,0.0};
423   GLdouble bly[4]={0.0,1.0,0.0,0.0};
424   GLdouble urx[4]={-1.0,0.0,0.0,0.0};
425   GLdouble ury[4]={0.0,-1.0,0.0,0.0};
426
427   for ( ; current != end; current++) {
428     FGPanelInstrument * instr = *current;
429     glPushMatrix();
430     glTranslated(instr->getXPos(), instr->getYPos(), 0);
431
432     int ix= instr->getWidth();
433     int iy= instr->getHeight();
434     glPushMatrix();
435     glTranslated(-ix/2,-iy/2,0);
436     glClipPlane(GL_CLIP_PLANE0,blx);
437     glClipPlane(GL_CLIP_PLANE1,bly);
438     glEnable(GL_CLIP_PLANE0);
439     glEnable(GL_CLIP_PLANE1);
440
441     glTranslated(ix,iy,0);
442     glClipPlane(GL_CLIP_PLANE2,urx);
443     glClipPlane(GL_CLIP_PLANE3,ury);
444     glEnable(GL_CLIP_PLANE2);
445     glEnable(GL_CLIP_PLANE3);
446     glPopMatrix();
447     instr->draw();
448
449     glPopMatrix();
450   }
451
452   glDisable(GL_CLIP_PLANE0);
453   glDisable(GL_CLIP_PLANE1);
454   glDisable(GL_CLIP_PLANE2);
455   glDisable(GL_CLIP_PLANE3);
456
457   // restore some original state
458   glPopAttrib();
459 }
460 #endif
461
462 /**
463  * Set the panel's background texture.
464  */
465 void
466 FGPanel::setBackground (FGCroppedTexture_ptr texture)
467 {
468   _bg = texture;
469 }
470
471 /**
472  * Set the panel's multiple background textures.
473  */
474 void
475 FGPanel::setMultiBackground (FGCroppedTexture_ptr texture, int idx)
476 {
477   _bg = 0;
478   _mbg[idx] = texture;
479 }
480
481 ////////////////////////////////////////////////////////////////////////
482 // Implementation of FGPanelTransformation.
483 ////////////////////////////////////////////////////////////////////////
484
485 FGPanelTransformation::FGPanelTransformation ()
486   : table(0)
487 {
488 }
489
490 FGPanelTransformation::~FGPanelTransformation ()
491 {
492   delete table;
493 }
494
495
496 \f
497 ////////////////////////////////////////////////////////////////////////
498 // Implementation of FGPanelInstrument.
499 ////////////////////////////////////////////////////////////////////////
500
501
502 FGPanelInstrument::FGPanelInstrument ()
503 {
504   setPosition(0, 0);
505   setSize(0, 0);
506 }
507
508 FGPanelInstrument::FGPanelInstrument (int x, int y, int w, int h)
509 {
510   setPosition(x, y);
511   setSize(w, h);
512 }
513
514 FGPanelInstrument::~FGPanelInstrument ()
515 {
516 }
517
518 void
519 FGPanelInstrument::setPosition (int x, int y)
520 {
521   _x = x;
522   _y = y;
523 }
524
525 void
526 FGPanelInstrument::setSize (int w, int h)
527 {
528   _w = w;
529   _h = h;
530 }
531
532 int
533 FGPanelInstrument::getXPos () const
534 {
535   return _x;
536 }
537
538 int
539 FGPanelInstrument::getYPos () const
540 {
541   return _y;
542 }
543
544 int
545 FGPanelInstrument::getWidth () const
546 {
547   return _w;
548 }
549
550 int
551 FGPanelInstrument::getHeight () const
552 {
553   return _h;
554 }
555
556 \f
557 ////////////////////////////////////////////////////////////////////////
558 // Implementation of FGLayeredInstrument.
559 ////////////////////////////////////////////////////////////////////////
560
561 FGLayeredInstrument::FGLayeredInstrument (int x, int y, int w, int h)
562   : FGPanelInstrument(x, y, w, h)
563 {
564 }
565
566 FGLayeredInstrument::~FGLayeredInstrument ()
567 {
568   for (layer_list::iterator it = _layers.begin(); it != _layers.end(); it++) {
569     delete *it;
570     *it = 0;
571   }
572 }
573
574 void
575 FGLayeredInstrument::draw ()
576 {
577   if (!test())
578     return;
579   
580   for (int i = 0; i < (int)_layers.size(); i++) {
581     glPushMatrix();
582     _layers[i]->draw();
583     glPopMatrix();
584   }
585 }
586
587 int
588 FGLayeredInstrument::addLayer (FGInstrumentLayer *layer)
589 {
590   int n = _layers.size();
591   if (layer->getWidth() == -1) {
592     layer->setWidth(getWidth());
593   }
594   if (layer->getHeight() == -1) {
595     layer->setHeight(getHeight());
596   }
597   _layers.push_back(layer);
598   return n;
599 }
600
601 int
602 FGLayeredInstrument::addLayer (FGCroppedTexture_ptr texture, int w, int h)
603 {
604   return addLayer(new FGTexturedLayer(texture, w, h));
605 }
606
607 void
608 FGLayeredInstrument::addTransformation (FGPanelTransformation * transformation)
609 {
610   int layer = _layers.size() - 1;
611   _layers[layer]->addTransformation(transformation);
612 }
613
614
615 \f
616 ////////////////////////////////////////////////////////////////////////
617 // Implementation of FGInstrumentLayer.
618 ////////////////////////////////////////////////////////////////////////
619
620 FGInstrumentLayer::FGInstrumentLayer (int w, int h)
621   : _w(w),
622     _h(h)
623 {
624 }
625
626 FGInstrumentLayer::~FGInstrumentLayer ()
627 {
628   for (transformation_list::iterator it = _transformations.begin();
629        it != _transformations.end();
630        it++) {
631     delete *it;
632     *it = 0;
633   }
634 }
635
636 void
637 FGInstrumentLayer::transform () const
638 {
639   transformation_list::const_iterator it = _transformations.begin();
640   transformation_list::const_iterator last = _transformations.end();
641   while (it != last) {
642     FGPanelTransformation *t = *it;
643     if (t->test()) {
644       float val = (t->node == 0 ? 0.0 : t->node->getFloatValue());
645
646       if (t->has_mod)
647           val = fmod(val, t->mod);
648       if (val < t->min) {
649         val = t->min;
650       } else if (val > t->max) {
651         val = t->max;
652       }
653
654       if (t->table==0) {
655         val = val * t->factor + t->offset;
656       } else {
657         val = t->table->interpolate(val) * t->factor + t->offset;
658      }
659       
660       switch (t->type) {
661       case FGPanelTransformation::XSHIFT:
662         glTranslatef(val, 0.0, 0.0);
663         break;
664       case FGPanelTransformation::YSHIFT:
665         glTranslatef(0.0, val, 0.0);
666         break;
667       case FGPanelTransformation::ROTATION:
668         glRotatef(-val, 0.0, 0.0, 1.0);
669         break;
670       }
671     }
672     it++;
673   }
674 }
675
676 void
677 FGInstrumentLayer::addTransformation (FGPanelTransformation * transformation)
678 {
679   _transformations.push_back(transformation);
680 }
681
682
683 \f
684 ////////////////////////////////////////////////////////////////////////
685 // Implementation of FGGroupLayer.
686 ////////////////////////////////////////////////////////////////////////
687
688 FGGroupLayer::FGGroupLayer ()
689 {
690 }
691
692 FGGroupLayer::~FGGroupLayer ()
693 {
694   for (unsigned int i = 0; i < _layers.size(); i++)
695     delete _layers[i];
696 }
697
698 void
699 FGGroupLayer::draw ()
700 {
701   if (test()) {
702     transform();
703     int nLayers = _layers.size();
704     for (int i = 0; i < nLayers; i++)
705       _layers[i]->draw( );
706   }
707 }
708
709 void
710 FGGroupLayer::addLayer (FGInstrumentLayer * layer)
711 {
712   _layers.push_back(layer);
713 }
714
715
716 \f
717 ////////////////////////////////////////////////////////////////////////
718 // Implementation of FGTexturedLayer.
719 ////////////////////////////////////////////////////////////////////////
720
721
722 FGTexturedLayer::FGTexturedLayer (FGCroppedTexture_ptr texture, int w, int h)
723   : FGInstrumentLayer(w, h),
724     _emissive(false),
725     displayList(0)
726 {
727   setTexture(texture);
728 }
729
730
731 FGTexturedLayer::~FGTexturedLayer ()
732 {
733 }
734
735 GLuint
736 FGTexturedLayer::getDisplayList()
737 {
738   if( displayList != 0 )
739     return displayList;
740
741   int w2 = _w / 2;
742   int h2 = _h / 2;
743
744   _texture->bind( false );
745   displayList = glGenLists(1);
746   glNewList(displayList,GL_COMPILE_AND_EXECUTE);
747     glBindTexture( GL_TEXTURE_2D, _texture->getTexture() );
748     glBegin(GL_QUADS);
749       glTexCoord2f(_texture->getMinX(), _texture->getMinY()); glVertex2f(-w2, -h2);
750       glTexCoord2f(_texture->getMaxX(), _texture->getMinY()); glVertex2f(w2, -h2);
751       glTexCoord2f(_texture->getMaxX(), _texture->getMaxY()); glVertex2f(w2, h2);
752       glTexCoord2f(_texture->getMinX(), _texture->getMaxY()); glVertex2f(-w2, h2);
753     glEnd();
754   glEndList();
755
756   return displayList;
757 }
758
759 void
760 FGTexturedLayer::draw ( )
761 {
762   if (test()) {
763     transform();
764     glCallList(getDisplayList());
765   }
766 }
767
768
769 \f
770 ////////////////////////////////////////////////////////////////////////
771 // Implementation of FGTextLayer.
772 ////////////////////////////////////////////////////////////////////////
773
774 fntRenderer FGTextLayer::text_renderer;
775
776 FGTextLayer::FGTextLayer (int w, int h)
777   : FGInstrumentLayer(w, h), _pointSize(14.0), _font_name("Helvetica.txf")
778 {
779   _then.stamp();
780   _color[0] = _color[1] = _color[2] = 0.0;
781   _color[3] = 1.0;
782 }
783
784 FGTextLayer::~FGTextLayer ()
785 {
786   chunk_list::iterator it = _chunks.begin();
787   chunk_list::iterator last = _chunks.end();
788   for ( ; it != last; it++) {
789     delete *it;
790   }
791 }
792
793 void
794 FGTextLayer::draw ()
795 {
796   if (test()) {
797     float c[4];
798     glGetFloatv( GL_CURRENT_COLOR, c );
799     glColor4fv(_color);
800     transform();
801
802     text_renderer.setFont(ApplicationProperties::fontCache.getTexFont(_font_name.c_str()));
803
804     text_renderer.setPointSize(_pointSize);
805     text_renderer.begin();
806     text_renderer.start3f(0, 0, 0);
807
808     _now.stamp();
809     long diff = (_now - _then).toUSecs();
810
811     if (diff > 100000 || diff < 0 ) {
812       // ( diff < 0 ) is a sanity check and indicates our time stamp
813       // difference math probably overflowed.  We can handle a max
814       // difference of 35.8 minutes since the returned value is in
815       // usec.  So if the panel is left off longer than that we can
816       // over flow the math with it is turned back on.  This (diff <
817       // 0) catches that situation, get's us out of trouble, and
818       // back on track.
819       recalc_value();
820       _then = _now;
821     }
822
823     // Something is goofy.  The code in this file renders only CCW
824     // polygons, and I have verified that the font code in plib
825     // renders only CCW trianbles.  Yet they come out backwards.
826     // Something around here or in plib is either changing the winding
827     // order or (more likely) pushing a left-handed matrix onto the
828     // stack.  But I can't find it; get out the chainsaw...
829     glFrontFace(GL_CW);
830     text_renderer.puts((char *)(_value.c_str()));
831     glFrontFace(GL_CCW);
832
833     text_renderer.end();
834     glColor4fv( c );
835   }
836 }
837
838 void
839 FGTextLayer::addChunk (FGTextLayer::Chunk * chunk)
840 {
841   _chunks.push_back(chunk);
842 }
843
844 void
845 FGTextLayer::setColor (float r, float g, float b)
846 {
847   _color[0] = r;
848   _color[1] = g;
849   _color[2] = b;
850   _color[3] = 1.0;
851 }
852
853 void
854 FGTextLayer::setPointSize (float size)
855 {
856   _pointSize = size;
857 }
858
859 void
860 FGTextLayer::setFontName(const string &name)
861 {
862   _font_name = name + ".txf";
863 }
864
865
866 void
867 FGTextLayer::setFont(fntFont * font)
868 {
869   FGTextLayer::text_renderer.setFont(font);
870 }
871
872
873 void
874 FGTextLayer::recalc_value () const
875 {
876   _value = "";
877   chunk_list::const_iterator it = _chunks.begin();
878   chunk_list::const_iterator last = _chunks.end();
879   for ( ; it != last; it++) {
880     _value += (*it)->getValue();
881   }
882 }
883
884
885 \f
886 ////////////////////////////////////////////////////////////////////////
887 // Implementation of FGTextLayer::Chunk.
888 ////////////////////////////////////////////////////////////////////////
889
890 FGTextLayer::Chunk::Chunk (const string &text, const string &fmt)
891   : _type(FGTextLayer::TEXT), _fmt(fmt)
892 {
893   _text = text;
894   if (_fmt.empty()) 
895     _fmt = "%s";
896 }
897
898 FGTextLayer::Chunk::Chunk (ChunkType type, const SGPropertyNode * node,
899                            const string &fmt, float mult, float offs,
900                            bool truncation)
901   : _type(type), _fmt(fmt), _mult(mult), _offs(offs), _trunc(truncation)
902 {
903   if (_fmt.empty()) {
904     if (type == TEXT_VALUE)
905       _fmt = "%s";
906     else
907       _fmt = "%.2f";
908   }
909   _node = node;
910 }
911
912 const char *
913 FGTextLayer::Chunk::getValue () const
914 {
915   if (test()) {
916     _buf[0] = '\0';
917     switch (_type) {
918     case TEXT:
919       sprintf(_buf, _fmt.c_str(), _text.c_str());
920       return _buf;
921     case TEXT_VALUE:
922       sprintf(_buf, _fmt.c_str(), _node->getStringValue());
923       break;
924     case DOUBLE_VALUE:
925       double d = _offs + _node->getFloatValue() * _mult;
926       if (_trunc)  d = (d < 0) ? -floor(-d) : floor(d);
927       sprintf(_buf, _fmt.c_str(), d);
928       break;
929     }
930     return _buf;
931   } else {
932     return "";
933   }
934 }
935
936
937 \f
938 ////////////////////////////////////////////////////////////////////////
939 // Implementation of FGSwitchLayer.
940 ////////////////////////////////////////////////////////////////////////
941
942 FGSwitchLayer::FGSwitchLayer ()
943   : FGGroupLayer()
944 {
945 }
946
947 void
948 FGSwitchLayer::draw ()
949 {
950   if (test()) {
951     transform();
952     int nLayers = _layers.size();
953     for (int i = 0; i < nLayers; i++) {
954       if (_layers[i]->test()) {
955           _layers[i]->draw();
956           return;
957       }
958     }
959   }
960 }
961
962 \f
963 // end of panel.cxx