]> git.mxchange.org Git - flightgear.git/commitdiff
Stuart Buchanan:
authorehofman <ehofman>
Fri, 6 Jan 2006 09:50:58 +0000 (09:50 +0000)
committerehofman <ehofman>
Fri, 6 Jan 2006 09:50:58 +0000 (09:50 +0000)
- Provide a Nasal interface to display simple text messages on the screen
  like the ATC display. In fact, I copied the code from the ATCDisplay.cxx
  and simply shifted it further down the screen.

Erik:

TODO: Integrate the two pieces of code.

src/Main/fg_init.cxx
src/Main/globals.hxx
src/Main/renderer.cxx
src/Scripting/Makefile.am
src/Scripting/NasalDisplay.cxx [new file with mode: 0644]
src/Scripting/NasalDisplay.hxx [new file with mode: 0644]
src/Scripting/NasalSys.cxx
src/Scripting/NasalSys.hxx

index 834c2dc6cf7536591a80375ad5f86104c0f1a88a..4b09eb83aba0a2ad3303dec9c57625023ca561f4 100644 (file)
 #include <Scenery/scenery.hxx>
 #include <Scenery/tilemgr.hxx>
 #include <Scripting/NasalSys.hxx>
+#include <Scripting/NasalDisplay.hxx>
 #include <Sound/fg_fx.hxx>
 #include <Sound/beacon.hxx>
 #include <Sound/morse.hxx>
@@ -1758,6 +1759,14 @@ bool fgInitSubsystems() {
     globals->get_io()->bind();
 
 
+    ////////////////////////////////////////////////////////////////////
+    // Initialise Nasal display system
+    ////////////////////////////////////////////////////////////////////
+
+    SG_LOG(SG_GENERAL, SG_INFO, "  Nasal Display");
+    globals->set_Nasal_display(new FGNasalDisplay);
+    globals->get_Nasal_display()->init(); 
+
     ////////////////////////////////////////////////////////////////////
     // Add a new 2D panel.
     ////////////////////////////////////////////////////////////////////
index c91df3c36ba01a12bdddb2eb32dc31cc3c4040f8..e59a6b79e175335697e765fd5ca0bbf516142d69 100644 (file)
@@ -73,6 +73,7 @@ class FGControls;
 class FGFlightPlanDispatcher;
 class FGIO;
 class FGNavList;
+class FGNasalDisplay;
 class FGTACANList;
 class FGFixList;
 class FGLight;
@@ -209,6 +210,9 @@ private:
     FGNavList *carrierlist;
     FGTACANList *channellist;
     FGFixList *fixlist;
+    
+    // Scripting display
+    FGNasalDisplay * Nasal_display;
 
 
 #ifdef FG_MPLAYER_AS
@@ -358,6 +362,9 @@ public:
     inline void set_tile_mgr ( FGTileMgr *t ) { tile_mgr = t; }
 
     inline FGIO* get_io() const { return io; }
+    
+    inline FGNasalDisplay *get_Nasal_display() const { return Nasal_display; }
+    inline void set_Nasal_display( FGNasalDisplay *d ) {Nasal_display = d; }    
 
     inline FGNavList *get_navlist() const { return navlist; }
     inline void set_navlist( FGNavList *n ) { navlist = n; }
index 0e25a71692b87ff8dbc98f349c8403d6137e3a59..40487bc8280d765b09f15217adc98d83d00fbf65 100644 (file)
@@ -66,6 +66,7 @@
 #include <Model/acmodel.hxx>
 #include <Scenery/scenery.hxx>
 #include <Scenery/tilemgr.hxx>
+#include <Scripting/NasalDisplay.hxx>
 #include <ATC/ATCdisplay.hxx>
 #include <GUI/new_gui.hxx>
 
@@ -746,6 +747,9 @@ FGRenderer::update( bool refresh_camera_settings ) {
     if((fgGetBool("/sim/atc/enabled")) || (fgGetBool("/sim/ai-traffic/enabled")))
         globals->get_ATC_display()->update(delta_time_sec);
 
+    // Update any messages from the Nasal System
+    globals->get_Nasal_display()->update(delta_time_sec);
+
     // update the panel subsystem
     if ( globals->get_current_panel() != NULL ) {
         globals->get_current_panel()->update(delta_time_sec);
index 468e969d782fe03c9caa925de7cca4d1ecc6d540..63b1944efe4922b536e66c0c0ae326656706ec89 100644 (file)
@@ -1,6 +1,8 @@
 noinst_LIBRARIES = libScripting.a
 
-libScripting_a_SOURCES = NasalSys.cxx NasalSys.hxx nasal-props.cxx
-# libScripting_a_SOURCES = scriptmgr.cxx scriptmgr.hxx NasalSys.cxx NasalSys.hxx
+libScripting_a_SOURCES = \
+       NasalSys.cxx NasalSys.hxx \
+       NasalDisplay.cxx NasalDisplay.hxx \
+       nasal-props.cxx
 
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
diff --git a/src/Scripting/NasalDisplay.cxx b/src/Scripting/NasalDisplay.cxx
new file mode 100644 (file)
index 0000000..aa59944
--- /dev/null
@@ -0,0 +1,239 @@
+// NasalDisplay.cxx - routines to display Nasal output
+//
+// Written by David Luff, started October 2001.
+//
+// Copyright (C) 2001  David C Luff - david.luff@nottingham.ac.uk
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifdef HAVE_WINDOWS_H
+#   include <windows.h>
+#endif
+
+#include <simgear/compiler.h>
+
+#include SG_GLU_H
+
+#include <simgear/props/props.hxx>
+
+#include <Include/general.hxx>
+#include <Main/fg_props.hxx>
+#include <GUI/gui.h>
+
+#include "NasalDisplay.hxx"
+
+
+// Constructor
+FGNasalDisplay::FGNasalDisplay() {
+       rep_msg = false;
+       change_msg_flag = false;
+       dsp_offset1 = 0.0;
+       dsp_offset2 = 0.0;
+}
+
+
+// Destructor
+FGNasalDisplay::~FGNasalDisplay() {
+}
+
+void FGNasalDisplay::init() {
+}
+
+void FGNasalDisplay::bind() {
+}
+
+void FGNasalDisplay::unbind() {
+}
+
+// update - this actually draws the visuals and should be called from the main Flightgear rendering loop.
+void FGNasalDisplay::update(double dt) {
+       
+       // These strings are used for temporary storage of the transmission string in order
+       // that the string we view only changes when the next repetition starts scrolling
+       // even though the master string (rep_msg_str) may change at any time.
+       static string msg1 = "";
+       static string msg2 = "";
+       
+       if( rep_msg || msgList.size() ) {
+               SGPropertyNode *xsize_node = fgGetNode("/sim/startup/xsize");
+               SGPropertyNode *ysize_node = fgGetNode("/sim/startup/ysize");
+               int iwidth   = xsize_node->getIntValue();
+               int iheight  = ysize_node->getIntValue();
+               
+               glMatrixMode( GL_PROJECTION );
+               glPushMatrix();
+               glLoadIdentity();
+               gluOrtho2D( 0, iwidth, 0, iheight );
+               glMatrixMode( GL_MODELVIEW );
+               glPushMatrix();
+               glLoadIdentity();
+               
+               glDisable( GL_DEPTH_TEST );
+               glDisable( GL_LIGHTING );
+               
+               glColor3f( 0.9, 0.4, 0.2 );
+               
+               float fps = general.get_frame_rate();
+               
+               if(rep_msg) {
+                       //cout << "dsp_offset1 = " << dsp_offset1 << " dsp_offset2 = " << dsp_offset2 << endl;
+                       if(dsp_offset1 == 0) {
+                               msg1 = rep_msg_str;
+                       }
+                       if(dsp_offset2 == 0) {
+                               msg2 = rep_msg_str;
+                       }
+                       // Check for the situation where one offset is negative and the message is changed
+                       if(change_msg_flag) {
+                               if(dsp_offset1 < 0) {
+                                       msg1 = rep_msg_str;
+                               } else if(dsp_offset2 < 0) {
+                                       msg2 = rep_msg_str;
+                               }
+                               change_msg_flag = false;
+                       }
+                       
+                       //      guiFnt.drawString( rep_msg_str.c_str(),
+                       //          int(iwidth - guiFnt.getStringWidth(buf) - 10 - (int)dsp_offset),
+                       //          (iheight - 20) );
+                       guiFnt.drawString( msg1.c_str(),
+                       int(iwidth - 10 - dsp_offset1),
+                       (iheight - 20) );
+                       guiFnt.drawString( msg2.c_str(),
+                       int(iwidth - 10 - dsp_offset2),
+                       (iheight - 20) );
+                       
+                       // Try to scroll at a frame rate independent speed
+                       // 40 pixels/second looks about right for now
+                       if(dsp_offset1 >= dsp_offset2) {
+                               dsp_offset1+=(40.0/fps);
+                               dsp_offset2 = dsp_offset1 - (rep_msg_str.size() * 10) - 100;
+                               if(dsp_offset1 > (iwidth + (rep_msg_str.size() * 10)))
+                                       dsp_offset1 = 0;
+                       } else {
+                               dsp_offset2+=(40.0/fps);
+                               dsp_offset1 = dsp_offset2 - (rep_msg_str.size() * 10) - 100;
+                               if(dsp_offset2 > (iwidth + (rep_msg_str.size() * 10)))
+                                       dsp_offset2 = 0;
+                       }
+                       
+               }
+               
+               if(msgList.size()) {
+                       //cout << "Attempting to render single message\n";
+                       // We have at least one non-repeating message to process
+                       if(fgGetBool("/ATC/display/scroll-single-messages")) {  // Scroll single messages across the screen.
+                               msgList_itr = msgList.begin();
+                               int i = 0;
+                               while(msgList_itr != msgList.end()) {
+                                       nasalMessage m = *msgList_itr;
+                                       //cout << "m.counter = " << m.counter << '\n';
+                                       if(m.dsp_offset > (iwidth + (m.msg.size() * 10))) {
+                                               //cout << "Stopping single message\n";
+                                               msgList_itr = msgList.erase(msgList_itr);
+                                       } else if(m.counter > m.start_count) {
+                                               //cout << "Drawing single message\n";
+                                               guiFnt.drawString( m.msg.c_str(),
+                                               int(iwidth - 10 - m.dsp_offset),
+                                               (iheight - 80) );
+                                               m.counter += dt;
+                                               m.dsp_offset += (80.0/fps);
+                                               msgList[i] = m;
+                                               ++msgList_itr;
+                                               ++i;
+                                       } else {
+                                               //cout << "Not yet started single message\n";
+                                               m.counter += dt;
+                                               msgList[i] = m;
+                                               ++msgList_itr;
+                                               ++i;
+                                       }
+                               }
+                       } else {        // Display single messages for a short period of time.
+                               msgList_itr = msgList.begin();
+                               int i = 0;
+                               while(msgList_itr != msgList.end()) {
+                                       nasalMessage m = *msgList_itr;
+                                       //cout << "m.counter = " << m.counter << '\n';
+                                       if(m.counter > m.stop_count) {
+                                               //cout << "Stopping single message\n";
+                                               msgList_itr = msgList.erase(msgList_itr);
+                                       } else if(m.counter > m.start_count) {
+                                               int pin = (((int)m.msg.size() * 8) >= iwidth ? 5 : (iwidth - (m.msg.size() * 8))/2);
+                                               //cout << m.msg << '\n';
+                                               //cout << "pin = " << pin << ", iwidth = " << iwidth << ", msg.size = " << m.msg.size() << '\n';
+                                               guiFnt.drawString( m.msg.c_str(), pin, (iheight - 80) );
+                                               m.counter += dt;
+                                               msgList[i] = m;
+                                               ++msgList_itr;
+                                               ++i;
+                                       } else {
+                                               m.counter += dt;
+                                               msgList[i] = m;
+                                               ++msgList_itr;
+                                               ++i;
+                                       }
+                               }
+                       }
+               }
+               glEnable( GL_DEPTH_TEST );
+               glEnable( GL_LIGHTING );
+               glMatrixMode( GL_PROJECTION );
+               glPopMatrix();
+               glMatrixMode( GL_MODELVIEW );
+               glPopMatrix();
+       }
+}
+
+void FGNasalDisplay::RegisterSingleMessage(const string& msg, double delay) {
+       //cout << msg << '\n';
+       nasalMessage m;
+       m.msg = msg;
+       m.repeating = false;
+       m.counter = 0.0;
+       m.start_count = delay;
+       m.stop_count = m.start_count + 5.0;             // Display for 5ish seconds for now - this might have to change eg. be related to length of message in future
+       //cout << "m.stop_count = " << m.stop_count << '\n';
+       m.id = 0;
+       m.dsp_offset = 0.0;
+       
+       msgList.push_back(m);
+       //cout << "Single message registered\n";
+}
+
+void FGNasalDisplay::RegisterRepeatingMessage(const string& msg) {
+       rep_msg = true;
+       rep_msg_str = msg;
+       return;
+}
+
+void FGNasalDisplay::ChangeRepeatingMessage(const string& newmsg) {
+       rep_msg_str = newmsg;
+       change_msg_flag = true;
+       return;
+}
+
+void FGNasalDisplay::CancelRepeatingMessage() {
+       rep_msg = false;
+       rep_msg_str = "";
+       dsp_offset1 = 0;
+       dsp_offset2 = 0;
+       return;
+}
+
diff --git a/src/Scripting/NasalDisplay.hxx b/src/Scripting/NasalDisplay.hxx
new file mode 100644 (file)
index 0000000..4d2d883
--- /dev/null
@@ -0,0 +1,93 @@
+// NasalDisplay.hxx - class to manage the graphical display of Nasal messages.
+//                  - mainly copied from ATCDisplay.hxx
+//
+// Written by David Luff, started October 2001.
+//
+// Copyright (C) 2001  David C Luff - david.luff@nottingham.ac.uk
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+#ifndef _FG_NASAL_DISPLAY_HXX
+#define _FG_NASAL_DISPLAY_HXX
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <simgear/structure/subsystem_mgr.hxx>
+
+#include <vector>
+#include <string>
+
+SG_USING_STD(vector);
+SG_USING_STD(string);
+
+struct nasalMessage {
+    string msg;
+    bool repeating;
+    double counter;            // count of how many seconds since the message was registered
+    double start_count;        // value of counter at which display should start (seconds)
+    double stop_count; // value of counter at which display should stop (seconds)
+    int id;
+       double dsp_offset;
+};
+
+// ASSUMPTION - with two radios the list won't be long so we don't need to map the id's
+typedef vector<nasalMessage> nasalMessageList;
+typedef nasalMessageList::iterator nasalMessageListIterator;
+
+class FGNasalDisplay : public SGSubsystem 
+{
+
+private:
+    bool rep_msg;              // Flag to indicate there is a repeating transmission to display
+    bool change_msg_flag;      // Flag to indicate that the repeating message has changed
+    double dsp_offset1;                // Used to set the correct position of scrolling display
+    double dsp_offset2;
+    string rep_msg_str;                // The repeating transmission to play
+    nasalMessageList msgList;
+    nasalMessageListIterator msgList_itr;
+
+public:
+    FGNasalDisplay();
+    ~FGNasalDisplay();
+
+    void init();
+
+    void bind();
+
+    void unbind();
+
+    // Display any registered messages
+    void update(double dt);
+
+    // Register a single message for display after a delay of delay seconds
+    // Will automatically stop displaying after a suitable interval.
+    void RegisterSingleMessage(const string& msg, double delay = 0.0);
+
+    // For now we will assume only one repeating message at once
+    // This is not really robust
+
+    // Register a continuously repeating message
+    void RegisterRepeatingMessage(const string& msg);
+
+    // Change a repeating message - assume that the message changes after the string has finished for now
+    void ChangeRepeatingMessage(const string& newmsg); 
+
+    // Cancel the current repeating message
+    void CancelRepeatingMessage();
+};
+
+#endif // _FG_ATC_DISPLAY_HXX
index 53b9f835728aa058df89fb51b76ea2a004a72ce3..4c8eddbb1295ddeaadd7412b8ac98feb880966c3 100644 (file)
@@ -16,6 +16,7 @@
 #include <Main/fg_props.hxx>
 
 #include "NasalSys.hxx"
+#include "NasalDisplay.hxx"
 
 // Read and return file contents in a single buffer.  Note use of
 // stat() to get the file size.  This is a win32 function, believe it
@@ -287,6 +288,17 @@ static naRef f_rand(naContext c, naRef me, int argc, naRef* args)
     return naNum(sg_random());
 }
 
+// Wrapper function for screenPrint
+static naRef f_screenPrint(naContext c, naRef me, int argc, naRef* args)
+{
+    if(argc != 1 || !naIsString(args[0]))
+        naRuntimeError(c, "bad arguments to screenPrint()");
+    naRef lmsg = args[0];
+    FGNasalSys* nasal = (FGNasalSys*)globals->get_subsystem("nasal");
+    nasal->screenPrint(naStr_data(lmsg));
+    return naNil();
+}
+
 // Table of extension functions.  Terminate with zeros.
 static struct { char* name; naCFunction func; } funcs[] = {
     { "getprop",   f_getprop },
@@ -298,6 +310,7 @@ static struct { char* name; naCFunction func; } funcs[] = {
     { "_cmdarg",  f_cmdarg },
     { "_interpolate",  f_interpolate },
     { "rand",  f_rand },
+    { "screenPrint", f_screenPrint },
     { 0, 0 }
 };
 
@@ -582,3 +595,8 @@ void FGNasalSys::setListener(int argc, naRef* args)
     node->addChangeListener(new FGNasalListener(handler, this, gcSave(handler)));
 }
 
+// functions providing access to the NasalDisplay - used to display text directly on the screen
+void FGNasalSys::screenPrint(const char* src)
+{
+  globals->get_Nasal_display()->RegisterSingleMessage(src, 0);
+}
index f3e756b5914cf03fe24c2421e46b9a0cd7f36fdd..1a1423bc6950aa63a774fb88db672382339ad543 100644 (file)
@@ -47,7 +47,9 @@ public:
 
     void createModule(const char* moduleName, const char* fileName,
                     const char* src, int len);
-
+                   
+    void screenPrint(const char* src);
+     
 private:
     friend class FGNasalScript;
     friend class FGNasalListener;
@@ -96,7 +98,8 @@ public:
     ~FGNasalScript() { _nas->gcRelease(_gcKey); }
 
     bool call() {
-        naCall(_nas->_context, _code, 0, 0, naNil(), naNil());
+        naRef n = naNil();
+        naCall(_nas->_context, _code, 0, &n, naNil(), naNil());
         return naGetError(_nas->_context) == 0;
     }