Stuart Buchanan:
- 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.
This commit is contained in:
parent
0b3164c312
commit
0e16419f0d
8 changed files with 379 additions and 4 deletions
|
@ -102,6 +102,7 @@
|
|||
#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.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
239
src/Scripting/NasalDisplay.cxx
Normal file
239
src/Scripting/NasalDisplay.cxx
Normal file
|
@ -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;
|
||||
}
|
||||
|
93
src/Scripting/NasalDisplay.hxx
Normal file
93
src/Scripting/NasalDisplay.hxx
Normal file
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue