+.*
Makefile
Debug/
Build
include(OldGNUInstallDirs)
endif(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
+# Warning when build is not an out-of-source build.
+string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" InSourceBuild)
+if(InSourceBuild)
+ message(WARNING "Avoid building inside the source tree!")
+ message(WARNING "Create a separate build directory instead (i.e. 'fgbuild') and call CMake from there: ")
+ message(WARNING " mkdir ../fgbuild && cd ../fgbuild && cmake ${CMAKE_SOURCE_DIR}")
+endif(InSourceBuild)
+
set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "add a postfix, usually d on windows")
set(CMAKE_RELEASE_POSTFIX "" CACHE STRING "add a postfix, usually empty on windows")
set(CMAKE_RELWITHDEBINFO_POSTFIX "" CACHE STRING "add a postfix, usually empty on windows")
--- /dev/null
+!include "MUI.nsh"
+
+!system 'osgversion --so-number > %TEMP%\osg-so-number.txt'
+!system 'osgversion --version-number > %TEMP%\osg-version.txt'
+
+!define /file OSGSoNumber $%TEMP%\osg-so-number.txt
+!define /file OSGVersion $%TEMP%\osg-version.txt
+!define /file FGVersion flightgear\version
+
+!echo "osg-so is ${OSGSoNumber}"
+
+Name "FlightGear Nightly vs2010"
+OutFile fgfs_win64_vs2010_nightly_${FGVersion}.exe
+
+; use LZMA for best compression
+SetCompressor /FINAL /SOLID lzma
+SetCompressorDictSize 64
+
+InstallDir $PROGRAMFILES\FlightGear64-nightly-2010
+
+; Request admin privileges for Windows Vista
+RequestExecutionLevel highest
+
+; don't hang around
+AutoCloseWindow true
+
+!define UninstallKey "Software\Microsoft\Windows\CurrentVersion\Uninstall\FlightGear64-nightly-2010"
+!define FGBinDir "install\msvc100-64\FlightGear\bin"
+!define FGRunDir "install\msvc100-64\fgrun"
+!define OSGInstallDir "install\msvc100-64\OpenSceneGraph"
+!define OSGPluginsDir "${OSGInstallDir}\bin\osgPlugins-${OSGVersion}"
+
+!define ThirdPartyBinDir "3rdParty.x64\bin"
+
+!define MUI_ICON "flightgear\package\flightgear.ico"
+!define MUI_UNICON "flightgear\package\flightgear.ico"
+
+!define MUI_HEADERIMAGE
+!define MUI_HEADERIMAGE_RIGHT
+!define MUI_HEADERIMAGE_BITMAP "flightgear\package\Win-NSIS\fg-install-header.bmp" ; optional
+
+
+
+;!define MUI_WELCOMEFINISHPAGE_BITMAP "welcome.bmp"
+;!define MUI_UNWELCOMEFINISHPAGE_BITMAP "welcome.bmp"
+
+!insertmacro MUI_PAGE_WELCOME
+; include GPL license page
+!insertmacro MUI_PAGE_LICENSE "flightgear\Copying"
+!insertmacro MUI_PAGE_DIRECTORY
+!insertmacro MUI_PAGE_INSTFILES
+
+!define MUI_FINISHPAGE_RUN $INSTDIR\fgrun.exe
+!define MUI_FINISHPAGE_RUN_TEXT "Run FlightGear now"
+!insertmacro MUI_PAGE_FINISH
+
+
+!insertmacro MUI_UNPAGE_CONFIRM
+!insertmacro MUI_UNPAGE_INSTFILES
+
+!insertmacro MUI_LANGUAGE "English"
+
+; The stuff to install
+Section "" ;No components page, name is not important
+
+ SetShellVarContext all
+ ; Set output path to the installation directory.
+ SetOutPath $INSTDIR
+
+ File ${FGBinDir}\fgfs.exe
+ File ${FGBinDir}\fgjs.exe
+ File ${FGRunDir}\bin\fgrun.exe
+
+ File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osg.dll
+ File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgDB.dll
+ File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgGA.dll
+ File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgParticle.dll
+ File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgText.dll
+ File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgUtil.dll
+ File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgViewer.dll
+ File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgSim.dll
+ File ${OSGInstallDir}\bin\osg${OSGSoNumber}-osgFX.dll
+
+ File ${OSGInstallDir}\bin\ot12-OpenThreads.dll
+
+ File ${ThirdPartyBinDir}\*.dll
+
+ ; VC runtime redistributables
+ File "$%VCINSTALLDIR%\redist\x64\Microsoft.VC100.CRT\*.dll"
+
+ File /r ${FGRunDir}\share\locale
+
+ SetOutPath $INSTDIR\osgPlugins-${OSGVersion}
+ File ${OSGPluginsDir}\osgdb_ac.dll
+ File ${OSGPluginsDir}\osgdb_osg.dll
+ File ${OSGPluginsDir}\osgdb_osga.dll
+ File ${OSGPluginsDir}\osgdb_3ds.dll
+ File ${OSGPluginsDir}\osgdb_mdl.dll
+ File ${OSGPluginsDir}\osgdb_jpeg.dll
+ File ${OSGPluginsDir}\osgdb_rgb.dll
+ File ${OSGPluginsDir}\osgdb_png.dll
+ File ${OSGPluginsDir}\osgdb_dds.dll
+ File ${OSGPluginsDir}\osgdb_txf.dll
+ File ${OSGPluginsDir}\osgdb_freetype.dll
+ File ${OSGPluginsDir}\osgdb_serializers_osg.dll
+ File ${OSGPluginsDir}\osgdb_serializers_osganimation.dll
+ File ${OSGPluginsDir}\osgdb_serializers_osgfx.dll
+ File ${OSGPluginsDir}\osgdb_serializers_osgmanipulator.dll
+ File ${OSGPluginsDir}\osgdb_serializers_osgparticle.dll
+ File ${OSGPluginsDir}\osgdb_serializers_osgshadow.dll
+ File ${OSGPluginsDir}\osgdb_serializers_osgsim.dll
+ File ${OSGPluginsDir}\osgdb_serializers_osgterrain.dll
+ File ${OSGPluginsDir}\osgdb_serializers_osgtext.dll
+ File ${OSGPluginsDir}\osgdb_serializers_osgvolume.dll
+ File ${OSGPluginsDir}\osgdb_deprecated_osg.dll
+ File ${OSGPluginsDir}\osgdb_deprecated_osgparticle.dll
+
+
+ Exec '"$INSTDIR\fgrun.exe" --silent --fg-exe="$INSTDIR\fgfs.exe" '
+
+ CreateDirectory "$SMPROGRAMS\FlightGear"
+ CreateShortCut "$SMPROGRAMS\FlightGear\FlightGear64-nightly-2010.lnk" "$INSTDIR\fgrun.exe"
+
+
+ WriteUninstaller "$INSTDIR\FlightGear_Uninstall.exe"
+
+ WriteRegStr HKLM ${UninstallKey} "DisplayName" "FlightGear64 Nightly (vs2010 build)"
+ WriteRegStr HKLM ${UninstallKey} "DisplayVersion" "${FGVersion}"
+ WriteRegStr HKLM ${UninstallKey} "UninstallString" "$INSTDIR\FlightGear_Uninstall.exe"
+ WriteRegStr HKLM ${UninstallKey} "UninstallPath" "$INSTDIR\FlightGear_Uninstall.exe"
+ WriteRegDWORD HKLM ${UninstallKey} "NoModify" 1
+ WriteRegDWORD HKLM ${UninstallKey} "NoRepair" 1
+ WriteRegStr HKLM ${UninstallKey} "URLInfoAbout" "http://www.flightgear.org/"
+
+SectionEnd
+
+
+
+Section "Uninstall"
+
+ SetShellVarContext all
+
+
+ Delete "$SMPROGRAMS\FlightGear\FlightGear64-nightly-2010.lnk"
+ ; only delete the FlightGear group if it's empty
+ RMDir "$SMPROGRAMS\FlightGear"
+
+ RMDir /r "$INSTDIR"
+
+ DeleteRegKey HKLM ${UninstallKey}
+
+SectionEnd
+
#ifndef OLD_ATC_MGR
// Derived classes wishing to use the response counter should
// call this from their own Update(...).
-void FGATC::Update(double dt) {
+void FGATC::update(double dt) {
#ifdef ENABLE_AUDIO_SUPPORT
bool active = _atc_external->getBoolValue() ||
freq = 0;
SetNoDisplay();
- Update(0); // one last update
+ update(0); // one last update
}
else
{
class FGATC {
friend class FGATISMgr;
public:
-
+
FGATC();
virtual ~FGATC();
-
- virtual void Init()=0;
-
+
+ virtual void init()=0;
+
// Run the internal calculations
// Derived classes should call this method from their own Update methods if they
// wish to use the response timer functionality.
- virtual void Update(double dt);
-
+ virtual void update(double dt);
+
// Indicate that this instance should output to the display if appropriate
inline void SetDisplay() { _display = true; }
inline atc_type GetType() { return _type; }
// Set the core ATC data
- void SetStation(flightgear::CommStation* sta);
+ void SetStation(flightgear::CommStation* sta);
inline const std::string& get_ident() { return ident; }
inline void set_ident(const std::string& id) { ident = id; }
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/exception.hxx>
-#include <Airports/simple.hxx>
-#include <ATC/CommStation.hxx>
#include <Main/fg_props.hxx>
#include "ATISmgr.hxx"
-#include "ATCutils.hxx"
#include "atis.hxx"
-using flightgear::CommStation;
-
FGATISMgr::FGATISMgr() :
_currentUnit(0),
- _maxCommRadios(4),
+ _maxCommRadios(4)
#ifdef ENABLE_AUDIO_SUPPORT
- voice(true),
- voice1(0)
-#else
- voice(false)
+ ,useVoice(true),
+ voice(0)
#endif
{
globals->set_ATIS_mgr(this);
for (unsigned int unit = 0;unit < _maxCommRadios; ++unit)
{
- delete radios[unit].station;
- radios[unit].station = NULL;
+ delete radios[unit];
+ radios[unit] = NULL;
}
#ifdef ENABLE_AUDIO_SUPPORT
- delete voice1;
+ delete voice;
#endif
}
-void FGATISMgr::bind()
-{
-}
-
-void FGATISMgr::unbind()
-{
-}
-
void FGATISMgr::init()
{
- lon_node = fgGetNode("/position/longitude-deg", true);
- lat_node = fgGetNode("/position/latitude-deg", true);
- elev_node = fgGetNode("/position/altitude-ft", true);
-
for (unsigned int unit = 0;unit < _maxCommRadios; ++unit)
{
- CommRadioData data;
- string ncunit;
if (unit < _maxCommRadios/2)
- ncunit = "comm[" + decimalNumeral(unit) + "]";
+ radios.push_back(new FGATIS("comm", unit));
else
- ncunit = "nav[" + decimalNumeral(unit - _maxCommRadios/2) + "]";
- string commbase = "/instrumentation/" + ncunit;
- string commfreq = commbase + "/frequencies/selected-mhz";
-
- data.freq = fgGetNode(commfreq.c_str(), true);
- data.station = new FGATIS(commbase);
- radios.push_back(data);
+ radios.push_back(new FGATIS("nav", unit - _maxCommRadios/2));
}
}
+
void FGATISMgr::update(double dt)
{
// update only runs every now and then (1-2 per second)
if (++_currentUnit >= _maxCommRadios)
_currentUnit = 0;
- FGATC* pStation = radios[_currentUnit].station;
- if (pStation)
- pStation->Update(dt * _maxCommRadios);
-
- // Search the tuned frequencies
- FreqSearch(_currentUnit);
+ FGATC* commRadio = radios[_currentUnit];
+ if (commRadio)
+ commRadio->update(dt * _maxCommRadios);
}
// Return a pointer to an appropriate voice for a given type of ATC
// at different airports in quick succession if a large enough selection are available.
FGATCVoice* FGATISMgr::GetVoicePointer(const atc_type& type)
{
+#ifdef ENABLE_AUDIO_SUPPORT
// TODO - implement me better - maintain a list of loaded voices and other voices!!
- if(voice)
+ if(useVoice)
{
switch(type)
{
case ATIS: case AWOS:
-#ifdef ENABLE_AUDIO_SUPPORT
// Delayed loading for all available voices, needed because the
// sound manager might not be initialized (at all) at this point.
// For now we'll do one hard-wired one
* subsequently switches /sim/sound/audible to true.
* (which is the right thing to do -- CLO) :-)
*/
- if (!voice1 && fgGetBool("/sim/sound/working")) {
- voice1 = new FGATCVoice;
+ if (!voice && fgGetBool("/sim/sound/working")) {
+ voice = new FGATCVoice;
try {
- voice = voice1->LoadVoice("default");
+ useVoice = voice->LoadVoice("default");
} catch ( sg_io_exception & e) {
SG_LOG(SG_ATC, SG_ALERT, "Unable to load default voice : "
<< e.getFormattedMessage().c_str());
- voice = false;
- delete voice1;
- voice1 = 0;
+ useVoice = false;
+ delete voice;
+ voice = 0;
}
}
- if (voice)
- return voice1;
-#endif
- return NULL;
+ return voice;
case TOWER:
return NULL;
case APPROACH:
return NULL;
}
}
+#endif
return NULL;
}
-
-class RangeFilter : public CommStation::Filter
-{
-public:
- RangeFilter( const SGGeod & pos ) :
- CommStation::Filter(),
- _cart(SGVec3d::fromGeod(pos)),
- _pos(pos)
- {
- }
-
- virtual bool pass(FGPositioned* aPos) const
- {
- flightgear::CommStation * stn = dynamic_cast<flightgear::CommStation*>(aPos);
- if( NULL == stn )
- return false;
-
- // do the range check in cartesian space, since the distances are potentially
- // large enough that the geodetic functions become unstable
- // (eg, station on opposite side of the planet)
- double rangeM = SGMiscd::max( stn->rangeNm(), 10.0 ) * SG_NM_TO_METER;
- double d2 = distSqr( aPos->cart(), _cart);
-
- return d2 <= (rangeM * rangeM);
- }
-private:
- SGVec3d _cart;
- SGGeod _pos;
-};
-
-// Search for ATC stations by frequency
-void FGATISMgr::FreqSearch(const unsigned int unit)
-{
- double frequency = radios[unit].freq->getDoubleValue();
-
- // Note: 122.375 must be rounded DOWN to 12237
- // in order to be consistent with apt.dat et cetera.
- int freqKhz = static_cast<int>(frequency * 100.0 + 0.25);
-
- _aircraftPos = SGGeod::fromDegFt(lon_node->getDoubleValue(),
- lat_node->getDoubleValue(), elev_node->getDoubleValue());
-
- RangeFilter rangeFilter(_aircraftPos );
- CommStation* sta = CommStation::findByFreq(freqKhz, _aircraftPos, &rangeFilter );
- radios[unit].station->SetStation(sta);
-}
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#ifndef _FG_ATCMGR_HXX
-#define _FG_ATCMGR_HXX
+#ifndef _FG_ATISMGR_HXX
+#define _FG_ATISMGR_HXX
-#include <simgear/structure/subsystem_mgr.hxx>
+#include <vector>
-#include <string>
-#include <list>
-#include <map>
+#include <simgear/structure/subsystem_mgr.hxx>
#include "ATC.hxx"
-namespace flightgear
-{
- class CommStation;
-}
-
-typedef struct
-{
- SGPropertyNode_ptr freq;
- FGATC* station;
-} CommRadioData;
-
class FGATISMgr : public SGSubsystem
{
-
private:
// A vector containing all comm radios
- typedef std::vector<CommRadioData> radio_list_type;
- radio_list_type radios;
-
- // Any member function of FGATISMgr is permitted to leave this iterator pointing
- // at any point in or at the end of the list.
- // Hence any new access must explicitly first check for atc_list.end() before dereferencing.
-
- // Position of the Users Aircraft
- SGGeod _aircraftPos;
-
- // Pointers to current users position
- SGPropertyNode_ptr lon_node;
- SGPropertyNode_ptr lat_node;
- SGPropertyNode_ptr elev_node;
+ std::vector<FGATC*> radios;
unsigned int _currentUnit;
unsigned int _maxCommRadios;
-
- // Voice related stuff
- bool voice; // Flag - true if we are using voice
+
#ifdef ENABLE_AUDIO_SUPPORT
- FGATCVoice* voice1;
+ bool useVoice; // Flag - true if we are using voice
+ FGATCVoice* voice;
#endif
public:
~FGATISMgr();
void init();
-
- void bind();
-
- void unbind();
-
void update(double dt);
// Return a pointer to an appropriate voice for a given type of ATC
FGATCVoice* GetVoicePointer(const atc_type& type);
private:
- // Search the specified radio for stations on the same frequency and in range.
- void FreqSearch(const unsigned int unit);
};
-#endif // _FG_ATCMGR_HXX
+#endif // _FG_ATISMGR_HXX
#include <Airports/runways.hxx>
#include <Airports/dynamics.hxx>
+#include <ATC/CommStation.hxx>
#include "ATCutils.hxx"
#include "ATISmgr.hxx"
using std::cout;
using boost::ref;
using boost::tie;
+using flightgear::CommStation;
-FGATIS::FGATIS(const string& commbase) :
+FGATIS::FGATIS(const std::string& name, int num) :
+ _name(name),
+ _num(num),
transmission(""),
trans_ident(""),
old_volume(0),
msg_OK(0),
attention(0),
_prev_display(0),
- _commbase(commbase)
+ _time_before_search_sec(0),
+ _last_frequency(0)
{
fgTie("/environment/attention", this, (int_getter)0, &FGATIS::attend);
+ _root = fgGetNode("/instrumentation", true)->getNode(_name, num, true);
+ _volume = _root->getNode("volume",true);
+ _serviceable = _root->getNode("serviceable",true);
+
+ if (name != "nav")
+ {
+ // only drive "operable" for non-nav instruments (nav radio drives this separately)
+ _operable = _root->getNode("operable",true);
+ _operable->setBoolValue(false);
+ }
+
+ _electrical = fgGetNode("/systems/electrical/outputs",true)->getNode(_name,num, true);
+ _atis = _root->getNode("atis",true);
+ _freq = _root->getNode("frequencies/selected-mhz",true);
+
+ // current position
+ _lon_node = fgGetNode("/position/longitude-deg", true);
+ _lat_node = fgGetNode("/position/latitude-deg", true);
+ _elev_node = fgGetNode("/position/altitude-ft", true);
+
+ // backward compatibility: some properties may not exist (but default to "ON")
+ if (!_serviceable->hasValue())
+ _serviceable->setBoolValue(true);
+ if (!_electrical->hasValue())
+ _electrical->setDoubleValue(24.0);
+
///////////////
// FIXME: This would be more flexible and more extensible
// if the mappings were taken from an XML file, not hard-coded ...
return pAtisMgr->GetVoicePointer(ATIS);
}
-void FGATIS::Init() {
+void FGATIS::init() {
// Nothing to see here. Move along.
}
// Main update function - checks whether we are displaying or not the correct message.
-void FGATIS::Update(double dt) {
+void FGATIS::update(double dt) {
cur_time = globals->get_time_params()->get_cur_time();
msg_OK = (msg_time < cur_time);
}
#endif
- if(_display)
+ double volume = 0;
+ if ((_electrical->getDoubleValue()>8) && _serviceable->getBoolValue())
+ {
+ _time_before_search_sec -= dt;
+ // radio is switched on and OK
+ if (_operable.valid())
+ _operable->setBoolValue(true);
+
+ // Search the tuned frequencies
+ search();
+
+ if (_display)
+ {
+ volume = _volume->getDoubleValue();
+ }
+ }
+ else
{
- string prop = _commbase + "/volume";
- double volume = globals->get_props()->getDoubleValue(prop.c_str());
+ // radio is OFF
+ if (_operable.valid())
+ _operable->setBoolValue(false);
+ _time_before_search_sec = 0;
+ }
-// Check if we need to update the message
-// - basically every hour and if the weather changes significantly at the station
-// If !_prev_display, the radio had been detuned for a while and our
-// "transmission" variable was lost when we were de-instantiated.
+ if (volume > 0.05)
+ {
+ // Check if we need to update the message
+ // - basically every hour and if the weather changes significantly at the station
+ // If !_prev_display, the radio had been detuned for a while and our
+ // "transmission" variable was lost when we were de-instantiated.
int changed = GenTransmission(!_prev_display, attention);
+
+ // update output property
TreeOut(msg_OK);
+
if (changed || volume != old_volume) {
- //cout << "ATIS calling ATC::render volume: " << volume << endl;
- Render(transmission, volume, _commbase, true);
+ // audio output enabled
+ Render(transmission, volume, _name, true);
old_volume = volume;
}
+ _prev_display = _display;
} else {
-// We shouldn't be displaying
- //cout << "ATIS.CXX - calling NoRender()..." << endl;
- NoRender(_commbase);
+ // silence
+ NoRender(_name);
+ _prev_display = false;
}
- _prev_display = _display;
attention = 0;
}
// http://localhost:5400/instrumentation/comm[1]
//
// (Also, if in debug mode, dump it to the console.)
-void FGATIS::TreeOut(int msg_OK){
- string prop = _commbase + "/atis";
- globals->get_props()->setStringValue(prop.c_str(),
- ("<pre>\n" + transmission_readable + "</pre>\n").c_str());
- SG_LOG(SG_ATC, SG_DEBUG, "**** ATIS active on: " << prop <<
+void FGATIS::TreeOut(int msg_OK)
+{
+ _atis->setStringValue("<pre>\n" + transmission_readable + "</pre>\n");
+ SG_LOG(SG_ATC, SG_DEBUG, "**** ATIS active on: " << _name <<
"transmission: " << transmission_readable);
}
+
+
+
+class RangeFilter : public CommStation::Filter
+{
+public:
+ RangeFilter( const SGGeod & pos ) :
+ CommStation::Filter(),
+ _cart(SGVec3d::fromGeod(pos)),
+ _pos(pos)
+ {
+ }
+
+ virtual bool pass(FGPositioned* aPos) const
+ {
+ flightgear::CommStation * stn = dynamic_cast<flightgear::CommStation*>(aPos);
+ if( NULL == stn )
+ return false;
+
+ // do the range check in cartesian space, since the distances are potentially
+ // large enough that the geodetic functions become unstable
+ // (eg, station on opposite side of the planet)
+ double rangeM = SGMiscd::max( stn->rangeNm(), 10.0 ) * SG_NM_TO_METER;
+ double d2 = distSqr( aPos->cart(), _cart);
+
+ return d2 <= (rangeM * rangeM);
+ }
+private:
+ SGVec3d _cart;
+ SGGeod _pos;
+};
+
+// Search for ATC stations by frequency
+void FGATIS::search(void)
+{
+ double frequency = _freq->getDoubleValue();
+
+ // Note: 122.375 must be rounded DOWN to 12237
+ // in order to be consistent with apt.dat et cetera.
+ int freqKhz = static_cast<int>(frequency * 100.0 + 0.25);
+
+ // throttle frequency searches
+ if ((freqKhz == _last_frequency)&&(_time_before_search_sec > 0))
+ return;
+
+ _last_frequency = freqKhz;
+ _time_before_search_sec = 4.0;
+
+ // Position of the Users Aircraft
+ SGGeod aircraftPos = SGGeod::fromDegFt(_lon_node->getDoubleValue(),
+ _lat_node->getDoubleValue(),
+ _elev_node->getDoubleValue());
+
+ RangeFilter rangeFilter(aircraftPos );
+ CommStation* sta = CommStation::findByFreq(freqKhz, aircraftPos, &rangeFilter );
+ SetStation(sta);
+ if (sta && sta->airport())
+ {
+ SG_LOG(SG_ATC, SG_DEBUG, "FGATIS " << _name << ": " << sta->airport()->name());
+ }
+ else
+ {
+ SG_LOG(SG_ATC, SG_DEBUG, "FGATIS " << _name << ": no station.");
+ }
+}
#include <simgear/compiler.h>
#include <simgear/timing/sg_time.hxx>
+#include <simgear/props/props.hxx>
#include "ATC.hxx"
-//DCL - a complete guess for now.
-#define FG_ATIS_DEFAULT_RANGE 30
-
typedef std::map<std::string,std::string> MSS;
class FGATIS : public FGATC {
-
- //atc_type type;
-
- // The actual ATIS transmission
- // This is generated from the prevailing conditions when required.
- // This is the version with markup, suitable for voice synthesis:
- std::string transmission;
-
- // Same as above, but in a form more readable as text.
- std::string transmission_readable;
-
- // for failure modeling
- std::string trans_ident; // transmitted ident
- double old_volume;
- bool atis_failed; // atis failed?
- time_t msg_time; // for moderating error messages
- time_t cur_time;
- int msg_OK;
- int attention;
-
- bool _prev_display; // Previous value of _display flag
- MSS _remap; // abbreviations to be expanded
-
- std::string _commbase;
-
- // Aircraft position
- // ATIS is actually a special case in that unlike other ATC eg.tower it doesn't actually know about
- // or the whereabouts of the aircraft it is transmitting to. However, to ensure consistancy of
- // operation with the other ATC classes the ATIS class must calculate range to the aircraft in order
- // to decide whether to render the transmission - hence the users plane details must be stored.
- //SGPropertyNode_ptr airplane_lon_node;
- //SGPropertyNode_ptr airplane_lat_node;
- //SGPropertyNode_ptr airplane_elev_node;
-
+
+ std::string _name;
+ int _num;
+
+ SGPropertyNode_ptr _root;
+ SGPropertyNode_ptr _volume;
+ SGPropertyNode_ptr _serviceable;
+ SGPropertyNode_ptr _operable;
+ SGPropertyNode_ptr _electrical;
+ SGPropertyNode_ptr _freq;
+ SGPropertyNode_ptr _atis;
+
+ // Pointers to current users position
+ SGPropertyNode_ptr _lon_node;
+ SGPropertyNode_ptr _lat_node;
+ SGPropertyNode_ptr _elev_node;
+
+ // The actual ATIS transmission
+ // This is generated from the prevailing conditions when required.
+ // This is the version with markup, suitable for voice synthesis:
+ std::string transmission;
+
+ // Same as above, but in a form more readable as text.
+ std::string transmission_readable;
+
+ // for failure modeling
+ std::string trans_ident; // transmitted ident
+ double old_volume;
+ bool atis_failed; // atis failed?
+ time_t msg_time; // for moderating error messages
+ time_t cur_time;
+ int msg_OK;
+ int attention;
+
+ bool _prev_display; // Previous value of _display flag
+ MSS _remap; // abbreviations to be expanded
+
+ // internal periodic station search timer
+ double _time_before_search_sec;
+ int _last_frequency;
+
public:
-
- FGATIS(const std::string& commbase);
- ~FGATIS(void);
- virtual void Init();
- void attend (int);
-
- //run the ATIS instance
- void Update(double dt);
-
- //inline void set_type(const atc_type tp) {type = tp;}
- inline const std::string& get_trans_ident() { return trans_ident; }
-
+
+ FGATIS(const std::string& name, int num);
+ ~FGATIS(void);
+ virtual void init();
+ void attend (int);
+
+ //run the ATIS instance
+ void update(double dt);
+
+ //inline void set_type(const atc_type tp) {type = tp;}
+ inline const std::string& get_trans_ident() { return trans_ident; }
+
protected:
virtual FGATCVoice* GetVoicePointer();
private:
- // Generate the ATIS transmission text:
- int GenTransmission(const int regen, const int special);
-
- // Put the text into the property tree
- // (and in debug mode, print it on the console):
- void TreeOut(int msgOK);
+ // Generate the ATIS transmission text:
+ int GenTransmission(const int regen, const int special);
+
+ // Put the text into the property tree
+ // (and in debug mode, print it on the console):
+ void TreeOut(int msgOK);
+
+ // Search the specified radio for stations on the same frequency and in range.
+ void search(void);
- friend std::istream& operator>> ( std::istream&, FGATIS& );
+ friend std::istream& operator>> ( std::istream&, FGATIS& );
};
template <class TBase> class FunctorBase {
public:
+ virtual ~FunctorBase() {}
virtual TBase * operator()( SGPropertyNode_ptr configNode ) = 0;
};
canvas_mgr.cxx
elements/element.cxx
elements/group.cxx
+ elements/map.cxx
elements/path.cxx
elements/text.cxx
+ gui_mgr.cxx
+ placement.cxx
+ property_based_element.cxx
+ property_based_mgr.cxx
property_helper.cxx
+ window.cxx
)
set(HEADERS
canvas_mgr.hxx
elements/element.hxx
elements/group.hxx
+ elements/map.hxx
elements/path.hxx
elements/text.hxx
+ gui_mgr.hxx
+ placement.hxx
+ property_based_element.hxx
+ property_based_mgr.hxx
property_helper.hxx
+ window.hxx
)
flightgear_component(Canvas "${SOURCES}" "${HEADERS}")
--- /dev/null
+// Mouse event
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef CANVAS_MOUSE_EVENT_HXX_
+#define CANVAS_MOUSE_EVENT_HXX_
+
+#include <osgGA/GUIEventAdapter>
+
+namespace canvas
+{
+
+ class MouseEvent
+ {
+ public:
+ typedef osgGA::GUIEventAdapter::EventType EventType;
+ typedef osgGA::GUIEventAdapter::ScrollingMotion Scroll;
+
+ MouseEvent(EventType type):
+ type(type),
+ x(-1), y(-1),
+ dx(0), dy(0),
+ button(-1),
+ state(-1),
+ mod(-1)
+ {}
+
+ EventType type;
+ int x, y,
+ dx, dy,
+ button, //<! Button for this event
+ state, //<! Current button state
+ mod; //<! Keyboard modifier state
+ Scroll scroll;
+ };
+
+} // namespace canvas
+
+#endif /* CANVAS_MOUSE_EVENT_HXX_ */
#include "canvas.hxx"
#include "elements/group.hxx"
+
+#include <Canvas/MouseEvent.hxx>
#include <Canvas/property_helper.hxx>
+#include <Main/globals.hxx>
+#include <Viewer/CameraGroup.hxx>
+#include <Viewer/renderer.hxx>
+
+#include <simgear/scene/util/RenderConstants.hxx>
#include <osg/Camera>
#include <osg/Geode>
#include <osgText/Text>
+#include <osgViewer/Viewer>
+#include <boost/algorithm/string/predicate.hpp>
#include <iostream>
-//------------------------------------------------------------------------------
-/**
- * Callback used to disable/enable rendering to the texture if it is not
- * visible
- */
-class CameraCullCallback:
- public osg::NodeCallback
+//----------------------------------------------------------------------------
+Canvas::CameraCullCallback::CameraCullCallback():
+ _render( true ),
+ _render_frame( 0 )
{
- public:
- CameraCullCallback():
- _render( true )
- {}
+}
- /**
- * Enable rendering for the next frame
- */
- void enableRendering()
- {
- _render = true;
- }
+//----------------------------------------------------------------------------
+void Canvas::CameraCullCallback::enableRendering()
+{
+ _render = true;
+}
- private:
+//----------------------------------------------------------------------------
+void Canvas::CameraCullCallback::operator()( osg::Node* node,
+ osg::NodeVisitor* nv )
+{
+ if( !_render && nv->getTraversalNumber() != _render_frame )
+ return;
- bool _render;
+ traverse(node, nv);
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- if( _render )
- {
- traverse(node, nv);
- _render = false;
- }
- }
-};
-
-/**
- * This callback is installed on every placement of the canvas in the scene to
- * only render the canvas if at least one placement is visible
- */
-class PlacementCullCallback:
- public osg::NodeCallback
-{
- public:
+ _render = false;
+ _render_frame = nv->getTraversalNumber();
+}
- PlacementCullCallback(Canvas* canvas, CameraCullCallback* camera_cull):
- _canvas( canvas ),
- _camera_cull( camera_cull )
- {}
+//----------------------------------------------------------------------------
+Canvas::CullCallback::CullCallback(CameraCullCallback* camera_cull):
+ _camera_cull( camera_cull )
+{
- private:
+}
- Canvas *_canvas;
- CameraCullCallback *_camera_cull;
+//----------------------------------------------------------------------------
+void Canvas::CullCallback::operator()( osg::Node* node,
+ osg::NodeVisitor* nv )
+{
+ if( nv->getTraversalMask() & simgear::MODEL_BIT )
+ _camera_cull->enableRendering();
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- _camera_cull->enableRendering();
- traverse(node, nv);
- }
-};
+ traverse(node, nv);
+}
//------------------------------------------------------------------------------
-Canvas::Canvas():
+Canvas::Canvas(SGPropertyNode* node):
+ PropertyBasedElement(node),
_size_x(-1),
_size_y(-1),
_view_width(-1),
_view_height(-1),
- _status(0),
+ _status(node, "status"),
+ _status_msg(node, "status-msg"),
+ _mouse_x(node, "mouse/x"),
+ _mouse_y(node, "mouse/y"),
+ _mouse_dx(node, "mouse/dx"),
+ _mouse_dy(node, "mouse/dy"),
+ _mouse_button(node, "mouse/button"),
+ _mouse_state(node, "mouse/state"),
+ _mouse_mod(node, "mouse/mod"),
+ _mouse_scroll(node, "mouse/scroll"),
+ _mouse_event(node, "mouse/event"),
_sampling_dirty(false),
_color_dirty(true),
- _node(0)
+ _root_group( new canvas::Group(node) ),
+ _render_always(false)
{
+ _status = 0;
setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
- CameraCullCallback *camera_callback = new CameraCullCallback;
- _camera_callback = camera_callback;
- _cull_callback = new PlacementCullCallback(this, camera_callback);
-}
-
-//------------------------------------------------------------------------------
-Canvas::~Canvas()
-{
- clearPlacements();
+ _camera_callback = new CameraCullCallback;
+ _cull_callback = new CullCallback(_camera_callback);
- unbind();
- _node = 0;
+ canvas::linkColorNodes
+ (
+ "color-background",
+ _node,
+ _color_background,
+ osg::Vec4f(0,0,0,1)
+ );
}
//------------------------------------------------------------------------------
-int Canvas::getStatus() const
-{
- return _status;
-}
-
-//------------------------------------------------------------------------------
-void Canvas::reset(SGPropertyNode* node)
+Canvas::~Canvas()
{
- if( node )
- SG_LOG
- (
- SG_GL,
- SG_INFO,
- "Canvas::reset() texture[" << node->getIndex() << "]"
- );
-
- unbind();
-
- _node = node;
- setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
-
- if( _node )
- {
- _root_group.reset( new canvas::Group(_node) );
- _node->tie
- (
- "size[0]",
- SGRawValueMethods<Canvas, int>( *this, &Canvas::getSizeX,
- &Canvas::setSizeX )
- );
- _node->tie
- (
- "size[1]",
- SGRawValueMethods<Canvas, int>( *this, &Canvas::getSizeY,
- &Canvas::setSizeY )
- );
- _node->tie
- (
- "view[0]",
- SGRawValueMethods<Canvas, int>( *this, &Canvas::getViewWidth,
- &Canvas::setViewWidth )
- );
- _node->tie
- (
- "view[1]",
- SGRawValueMethods<Canvas, int>( *this, &Canvas::getViewHeight,
- &Canvas::setViewHeight )
- );
- _node->tie
- (
- "status",
- SGRawValueMethods<Canvas, int>(*this, &Canvas::getStatus)
- );
- _node->tie
- (
- "status-msg",
- SGRawValueMethods<Canvas, const char*>(*this, &Canvas::getStatusMsg)
- );
- _node->addChangeListener(this);
- canvas::linkColorNodes
- (
- "color-background",
- _node,
- _color_background,
- osg::Vec4f(0,0,0,1)
- );
- }
}
//------------------------------------------------------------------------------
// New placement
_placements.resize(node->getIndex() + 1);
else
- // Remove maybe already existing placements
- clearPlacements(node->getIndex());
-
- // add new placements
- _placements[node->getIndex()] = _texture.set_texture(
- node,
- _texture.getTexture(),
- _cull_callback
- );
+ // Remove possibly existing placements
+ _placements[ node->getIndex() ].clear();
+
+ // Get new placements
+ PlacementFactoryMap::const_iterator placement_factory =
+ _placement_factories.find( node->getStringValue("type", "object") );
+ if( placement_factory != _placement_factories.end() )
+ {
+ canvas::Placements& placements =
+ _placements[ node->getIndex() ] =
+ placement_factory->second
+ (
+ node,
+ boost::shared_static_cast<Canvas>(_self.lock())
+ );
+ node->setStringValue
+ (
+ "status-msg",
+ placements.empty() ? "No match" : "Ok"
+ );
+ }
+ else
+ node->setStringValue("status-msg", "Unknown placement type");
}
+
+ if( _render_always )
+ _camera_callback->enableRendering();
}
//------------------------------------------------------------------------------
setStatusFlags(CREATE_FAILED, false);
}
-//------------------------------------------------------------------------------
-int Canvas::getSizeX() const
-{
- return _size_x;
-}
-
//------------------------------------------------------------------------------
void Canvas::setSizeY(int sy)
{
setStatusFlags(CREATE_FAILED, false);
}
-//------------------------------------------------------------------------------
-int Canvas::getSizeY() const
-{
- return _size_y;
-}
-
//------------------------------------------------------------------------------
void Canvas::setViewWidth(int w)
{
_texture.setViewSize(_view_width, _view_height);
}
-//------------------------------------------------------------------------------
-int Canvas::getViewWidth() const
-{
- return _view_width;
-}
-
//------------------------------------------------------------------------------
void Canvas::setViewHeight(int h)
{
}
//------------------------------------------------------------------------------
-int Canvas::getViewHeight() const
+bool Canvas::handleMouseEvent(const canvas::MouseEvent& event)
{
- return _view_height;
-}
-
-//------------------------------------------------------------------------------
-const char* Canvas::getStatusMsg() const
-{
- return _status_msg.c_str();
+ _mouse_x = event.x;
+ _mouse_y = event.y;
+ _mouse_dx = event.dx;
+ _mouse_dy = event.dy;
+ _mouse_button = event.button;
+ _mouse_state = event.state;
+ _mouse_mod = event.mod;
+ _mouse_scroll = event.scroll;
+ // Always set event type last because all listeners are attached to it
+ _mouse_event = event.type;
+ return true;
}
//------------------------------------------------------------------------------
return;
if( child->getNameString() == "placement" )
- clearPlacements(child->getIndex());
+ _placements[ child->getIndex() ].clear();
else
static_cast<canvas::Element*>(_root_group.get())
->childRemoved(parent, child);
//----------------------------------------------------------------------------
void Canvas::valueChanged(SGPropertyNode* node)
{
+ if( boost::starts_with(node->getNameString(), "status") )
+ return;
+
if( node->getParent()->getParent() == _node )
{
if( !_color_background.empty()
|| node->getNameString() == "coverage-samples"
|| node->getNameString() == "color-samples" )
_sampling_dirty = true;
+ else if( node->getNameString() == "render-always" )
+ _render_always = node->getBoolValue();
+ else if( node->getNameString() == "size" )
+ {
+ if( node->getIndex() == 0 )
+ setSizeX( node->getIntValue() );
+ else if( node->getIndex() == 1 )
+ setSizeY( node->getIntValue() );
+ }
+ else if( node->getNameString() == "view" )
+ {
+ if( node->getIndex() == 0 )
+ setViewWidth( node->getIntValue() );
+ else if( node->getIndex() == 1 )
+ setViewHeight( node->getIntValue() );
+ }
}
_root_group->valueChanged(node);
}
+//------------------------------------------------------------------------------
+osg::Texture2D* Canvas::getTexture() const
+{
+ return _texture.getTexture();
+}
+
+//------------------------------------------------------------------------------
+GLuint Canvas::getTexId() const
+{
+ osg::Texture2D* tex = _texture.getTexture();
+ if( !tex )
+ return 0;
+
+// osgViewer::Viewer::Contexts contexts;
+// globals->get_renderer()->getViewer()->getContexts(contexts);
+//
+// if( contexts.empty() )
+// return 0;
+
+ osg::Camera* guiCamera =
+ flightgear::getGUICamera(flightgear::CameraGroup::getDefault());
+
+ osg::State* state = guiCamera->getGraphicsContext()->getState(); //contexts[0]->getState();
+ if( !state )
+ return 0;
+
+ osg::Texture::TextureObject* tobj =
+ tex->getTextureObject( state->getContextID() );
+ if( !tobj )
+ return 0;
+
+ return tobj->_id;
+}
+
+//------------------------------------------------------------------------------
+Canvas::CameraCullCallbackPtr Canvas::getCameraCullCallback() const
+{
+ return _camera_callback;
+}
+
+//----------------------------------------------------------------------------
+Canvas::CullCallbackPtr Canvas::getCullCallback() const
+{
+ return _cull_callback;
+}
+
+//------------------------------------------------------------------------------
+void Canvas::addPlacementFactory( const std::string& type,
+ canvas::PlacementFactory factory )
+{
+ if( _placement_factories.find(type) != _placement_factories.end() )
+ SG_LOG
+ (
+ SG_GENERAL,
+ SG_WARN,
+ "Canvas::addPlacementFactory: replace existing factor for type " << type
+ );
+
+ _placement_factories[type] = factory;
+}
+
//------------------------------------------------------------------------------
void Canvas::setStatusFlags(unsigned int flags, bool set)
{
if( set )
- _status |= flags;
+ _status = _status | flags;
else
- _status &= ~flags;
+ _status = _status & ~flags;
+ // TODO maybe extend simgear::PropertyObject to allow |=, &= etc.
if( (_status & MISSING_SIZE_X) && (_status & MISSING_SIZE_Y) )
_status_msg = "Missing size";
}
//------------------------------------------------------------------------------
-void Canvas::clearPlacements(int index)
-{
- Placements& placements = _placements.at(index);
- while( !placements.empty() )
- {
- osg::ref_ptr<osg::Group> group = placements.back();
- placements.pop_back();
-
- assert( group->getNumChildren() == 1 );
- osg::Node *child = group->getChild(0);
-
- if( group->getNumParents() )
- {
- osg::Group *parent = group->getParent(0);
- parent->addChild(child);
- parent->removeChild(group);
- }
-
- group->removeChild(child);
- }
-}
-
-//------------------------------------------------------------------------------
-void Canvas::clearPlacements()
-{
- for(size_t i = 0; i < _placements.size(); ++i)
- clearPlacements(i);
- _placements.clear();
-}
-
-//------------------------------------------------------------------------------
-void Canvas::unbind()
-{
- if( !_node )
- return;
-
- _node->untie("size[0]");
- _node->untie("size[1]");
- _node->untie("view[0]");
- _node->untie("view[1]");
- _node->untie("status");
- _node->untie("status-msg");
- _node->removeChangeListener(this);
-}
+Canvas::PlacementFactoryMap Canvas::_placement_factories;
#ifndef CANVAS_HXX_
#define CANVAS_HXX_
+#include "placement.hxx"
+#include "property_based_element.hxx"
+
+#include <Canvas/canvas_fwd.hpp>
#include <Instrumentation/od_gauge.hxx>
-#include <simgear/props/props.hxx>
+
+#include <simgear/props/propertyObject.hxx>
#include <osg/NodeCallback>
#include <memory>
#include <string>
-namespace canvas
-{
- class Group;
-}
-
class Canvas:
- public SGPropertyChangeListener
+ public PropertyBasedElement
{
public:
CREATE_FAILED = 0x0004
};
- Canvas();
+ /**
+ * Callback used to disable/enable rendering to the texture if it is not
+ * visible
+ */
+ class CameraCullCallback:
+ public osg::NodeCallback
+ {
+ public:
+ CameraCullCallback();
+
+ /**
+ * Enable rendering for the next frame
+ */
+ void enableRendering();
+
+ private:
+ bool _render;
+ unsigned int _render_frame;
+
+ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
+ };
+ typedef osg::ref_ptr<CameraCullCallback> CameraCullCallbackPtr;
+
+ /**
+ * This callback is installed on every placement of the canvas in the
+ * scene to only render the canvas if at least one placement is visible
+ */
+ class CullCallback:
+ public osg::NodeCallback
+ {
+ public:
+ CullCallback(CameraCullCallback* camera_cull);
+
+ private:
+ CameraCullCallback *_camera_cull;
+
+ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
+ };
+ typedef osg::ref_ptr<CullCallback> CullCallbackPtr;
+
+ Canvas(SGPropertyNode* node);
virtual ~Canvas();
- void reset(SGPropertyNode* node);
void update(double delta_time_sec);
+ int getSizeX() const
+ { return _size_x; }
+
+ int getSizeY() const
+ { return _size_y; }
+
void setSizeX(int sx);
- int getSizeX() const;
-
void setSizeY(int sy);
- int getSizeY() const;
void setViewWidth(int w);
- int getViewWidth() const;
-
void setViewHeight(int h);
- int getViewHeight() const;
- int getStatus() const;
- const char* getStatusMsg() const;
+ bool handleMouseEvent(const canvas::MouseEvent& event);
virtual void childAdded( SGPropertyNode * parent,
SGPropertyNode * child );
SGPropertyNode * child );
virtual void valueChanged (SGPropertyNode * node);
+ osg::Texture2D* getTexture() const;
+ GLuint getTexId() const;
+
+ CameraCullCallbackPtr getCameraCullCallback() const;
+ CullCallbackPtr getCullCallback() const;
+
+ static void addPlacementFactory( const std::string& type,
+ canvas::PlacementFactory factory );
+
private:
Canvas(const Canvas&); // = delete;
_view_width,
_view_height;
- int _status;
- std::string _status_msg;
+ simgear::PropertyObject<int> _status;
+ simgear::PropertyObject<std::string> _status_msg;
+
+ simgear::PropertyObject<int> _mouse_x, _mouse_y,
+ _mouse_dx, _mouse_dy,
+ _mouse_button,
+ _mouse_state,
+ _mouse_mod,
+ _mouse_scroll,
+ _mouse_event;
bool _sampling_dirty,
_color_dirty;
FGODGauge _texture;
std::auto_ptr<canvas::Group> _root_group;
- SGPropertyNode_ptr _node;
std::vector<SGPropertyNode_ptr> _color_background;
- osg::ref_ptr<osg::NodeCallback> _camera_callback;
- osg::ref_ptr<osg::NodeCallback> _cull_callback;
+ CameraCullCallbackPtr _camera_callback;
+ CullCallbackPtr _cull_callback;
+ bool _render_always; //<! Used to disable automatic lazy rendering (culling)
+
std::vector<SGPropertyNode*> _dirty_placements;
- std::vector<Placements> _placements;
+ std::vector<canvas::Placements> _placements;
- void setStatusFlags(unsigned int flags, bool set = true);
- void clearPlacements(int index);
- void clearPlacements();
+ typedef std::map<std::string, canvas::PlacementFactory> PlacementFactoryMap;
+ static PlacementFactoryMap _placement_factories;
- void unbind();
+ void setStatusFlags(unsigned int flags, bool set = true);
};
#endif /* CANVAS_HXX_ */
--- /dev/null
+// Canvas forward declarations
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef CANVAS_FWD_HPP_
+#define CANVAS_FWD_HPP_
+
+#include <boost/function.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <vector>
+
+class SGPropertyNode;
+
+class Canvas;
+typedef boost::shared_ptr<Canvas> CanvasPtr;
+typedef boost::weak_ptr<Canvas> CanvasWeakPtr;
+
+class PropertyBasedElement;
+typedef boost::shared_ptr<PropertyBasedElement> PropertyBasedElementPtr;
+typedef boost::weak_ptr<PropertyBasedElement> PropertyBasedElementWeakPtr;
+
+namespace canvas
+{
+ class Group;
+ class MouseEvent;
+
+ class Placement;
+ typedef boost::shared_ptr<Placement> PlacementPtr;
+ typedef std::vector<PlacementPtr> Placements;
+ typedef boost::function<Placements( const SGPropertyNode*,
+ CanvasPtr )> PlacementFactory;
+
+ class Window;
+ typedef boost::shared_ptr<Window> WindowPtr;
+ typedef boost::weak_ptr<Window> WindowWeakPtr;
+}
+
+#endif /* CANVAS_FWD_HPP_ */
#include "canvas_mgr.hxx"
#include "canvas.hxx"
-#include <Main/fg_props.hxx>
+#include <boost/bind.hpp>
-#include <osg/Camera>
-#include <osg/Texture2D>
-
-#include <stdexcept>
-#include <string>
-
-//------------------------------------------------------------------------------
-CanvasMgr::CanvasMgr():
- _props( fgGetNode("/canvas", true) )
-{
-
-}
-
-//------------------------------------------------------------------------------
-CanvasMgr::~CanvasMgr()
-{
-
-}
-
-//------------------------------------------------------------------------------
-void CanvasMgr::init()
-{
- _props->addChangeListener(this);
- triggerChangeRecursive(_props);
-}
-
-//------------------------------------------------------------------------------
-void CanvasMgr::reinit()
-{
-
-}
-
-//------------------------------------------------------------------------------
-void CanvasMgr::shutdown()
-{
- _props->removeChangeListener(this);
-}
-
-//------------------------------------------------------------------------------
-void CanvasMgr::bind()
+typedef boost::shared_ptr<Canvas> CanvasPtr;
+CanvasPtr canvasFactory(SGPropertyNode* node)
{
+ return CanvasPtr(new Canvas(node));
}
-//------------------------------------------------------------------------------
-void CanvasMgr::unbind()
-{
-}
//------------------------------------------------------------------------------
-void CanvasMgr::update(double delta_time_sec)
-{
- for( size_t i = 0; i < _canvases.size(); ++i )
- if( _canvases[i] )
- _canvases[i]->update(delta_time_sec);
-}
-
-//------------------------------------------------------------------------------
-void CanvasMgr::childAdded( SGPropertyNode * parent,
- SGPropertyNode * child )
-{
- if( parent != _props )
- return;
-
- if( child->getNameString() == "texture" )
- textureAdded(child);
-}
-
-//------------------------------------------------------------------------------
-void CanvasMgr::childRemoved( SGPropertyNode * parent,
- SGPropertyNode * child )
-{
- if( parent != _props )
- return;
-
- if( child->getNameString() == "texture" )
- {
- size_t index = child->getIndex();
-
- if( index >= _canvases.size() )
- SG_LOG(SG_GL, SG_WARN, "can't removed unknown texture[" << index << "]!");
- else
- // remove the canvas...
- _canvases[index].reset();
- }
-}
-
-//------------------------------------------------------------------------------
-void CanvasMgr::textureAdded(SGPropertyNode* node)
+CanvasMgr::CanvasMgr():
+ PropertyBasedMgr("/canvas", "texture", &canvasFactory)
{
- size_t index = node->getIndex();
-
- if( index >= _canvases.size() )
- {
- if( index > _canvases.size() )
- SG_LOG(SG_GL, SG_WARN, "Skipping unused texture slot(s)!");
-
- _canvases.resize(index + 1);
- }
- else
- {
- SG_LOG(SG_GL, SG_WARN, "texture[" << index << "] already exists!");
- }
-
- _canvases[index].reset( new Canvas() );
- _canvases[index]->reset(node);
+ Canvas::addPlacementFactory
+ (
+ "object",
+ boost::bind
+ (
+ &FGODGauge::set_texture,
+ _1,
+ boost::bind(&Canvas::getTexture, _2),
+ boost::bind(&Canvas::getCullCallback, _2)
+ )
+ );
}
//------------------------------------------------------------------------------
-void CanvasMgr::triggerChangeRecursive(SGPropertyNode* node)
+unsigned int CanvasMgr::getCanvasTexId(size_t index) const
{
- node->getParent()->fireChildAdded(node);
-
- if( node->nChildren() == 0 && node->getType() != simgear::props::NONE )
- return node->fireValueChanged();
+ if( index >= _elements.size()
+ || !_elements[index] )
+ return 0;
- for( int i = 0; i < node->nChildren(); ++i )
- triggerChangeRecursive( node->getChild(i) );
+ return static_cast<Canvas*>(_elements[index].get())->getTexId();
}
#ifndef CANVAS_MGR_H_
#define CANVAS_MGR_H_
-#include <simgear/props/props.hxx>
-#include <simgear/structure/subsystem_mgr.hxx>
-
-#include <boost/shared_ptr.hpp>
-#include <vector>
-
-class Canvas;
-typedef boost::shared_ptr<Canvas> CanvasPtr;
+#include "property_based_mgr.hxx"
class CanvasMgr:
- public SGSubsystem,
- public SGPropertyChangeListener
+ public PropertyBasedMgr
{
public:
CanvasMgr();
- virtual ~CanvasMgr();
-
- virtual void init();
- virtual void reinit();
- virtual void shutdown();
-
- virtual void bind();
- virtual void unbind();
-
- virtual void update(double delta_time_sec);
-
- virtual void childAdded( SGPropertyNode * parent,
- SGPropertyNode * child );
- virtual void childRemoved( SGPropertyNode * parent,
- SGPropertyNode * child );
-
- private:
-
- /** Root node for everything concerning the canvas system */
- SGPropertyNode_ptr _props;
-
- /** The actual canvases */
- std::vector<CanvasPtr> _canvases;
-
- void textureAdded(SGPropertyNode* node);
/**
- * Trigger a childAdded and valueChanged event for every child of node
- * (Unlimited depth) and node itself.
+ * Get OpenGL texture name for given canvas
+ *
+ * @param Index of canvas
+ * @return OpenGL texture name
*/
- void triggerChangeRecursive(SGPropertyNode* node);
-
+ unsigned int getCanvasTexId(size_t index) const;
};
#endif /* CANVAS_MGR_H_ */
//----------------------------------------------------------------------------
void Element::update(double dt)
{
+ if( !_transform->getNodeMask() )
+ // Don't do anything if element is hidden
+ return;
+
if( _transform_dirty )
{
osg::Matrix m;
type = TT_ROTATE;
else if( name == "s" )
type = TT_SCALE;
- else
- SG_LOG
- (
- SG_GL,
- SG_WARN,
- "Unknown transform element " << child->getPath()
- );
_transform_dirty = true;
}
{
if( child->getNameString() == "update" )
update(0);
+ else if( child->getNameString() == "visible" )
+ // TODO check if we need another nodemask
+ _transform->setNodeMask( child->getBoolValue() ? 0xffffffff : 0 );
else
childChanged(child);
}
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "group.hxx"
+#include "map.hxx"
#include "path.hxx"
#include "text.hxx"
element.reset( new Text(child) );
else if( child->getNameString() == "group" )
element.reset( new Group(child) );
+ else if( child->getNameString() == "map" )
+ element.reset( new Map(child) );
else if( child->getNameString() == "path" )
element.reset( new Path(child) );
{
if( node->getNameString() == "text"
|| node->getNameString() == "group"
- || node->getNameString() == "path")
+ || node->getNameString() == "map"
+ || node->getNameString() == "path" )
{
ChildMap::iterator child = _children.find(node);
--- /dev/null
+// A group of 2D canvas elements which get automatically transformed according
+// to the map parameters.
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#include "map.hxx"
+#include "map/geo_node_pair.hxx"
+#include "map/projection.hxx"
+
+#include <Main/fg_props.hxx>
+#include <cmath>
+
+#define LOG_GEO_RET(msg) \
+ {\
+ SG_LOG\
+ (\
+ SG_GENERAL,\
+ SG_WARN,\
+ msg << " (" << child->getStringValue()\
+ << ", " << child->getPath() << ")"\
+ );\
+ return;\
+ }
+
+namespace canvas
+{
+
+ // TODO make projection configurable
+ SansonFlamsteedProjection projection;
+ const std::string GEO = "-geo";
+
+ //----------------------------------------------------------------------------
+ Map::Map(SGPropertyNode_ptr node):
+ Group(node),
+ _projection_dirty(true)
+ {
+
+ }
+
+ //----------------------------------------------------------------------------
+ Map::~Map()
+ {
+
+ }
+
+ //----------------------------------------------------------------------------
+ void Map::update(double dt)
+ {
+ for( GeoNodes::iterator it = _geo_nodes.begin();
+ it != _geo_nodes.end();
+ ++it )
+ {
+ GeoNodePair* geo_node = it->second.get();
+ if( !geo_node->isComplete()
+ || (!geo_node->isDirty() && !_projection_dirty) )
+ continue;
+
+ GeoCoord lat = parseGeoCoord(geo_node->getLat());
+ if( lat.type != GeoCoord::LATITUDE )
+ continue;
+
+ GeoCoord lon = parseGeoCoord(geo_node->getLon());
+ if( lon.type != GeoCoord::LONGITUDE )
+ continue;
+
+ Projection::ScreenPosition pos =
+ projection.worldToScreen(lat.value, lon.value);
+
+ geo_node->setScreenPos(pos.x, pos.y);
+
+// geo_node->print();
+ geo_node->setDirty(false);
+ }
+ _projection_dirty = false;
+
+ Group::update(dt);
+ }
+
+ //----------------------------------------------------------------------------
+ void Map::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ if( !hasSuffix(child->getNameString(), GEO) )
+ return Element::childAdded(parent, child);
+
+ _geo_nodes[child].reset(new GeoNodePair());
+ }
+
+ //----------------------------------------------------------------------------
+ void Map::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
+ {
+ if( !hasSuffix(child->getNameString(), GEO) )
+ return Element::childRemoved(parent, child);
+
+ // TODO remove from other node
+ _geo_nodes.erase(child);
+ }
+
+ //----------------------------------------------------------------------------
+ void Map::valueChanged(SGPropertyNode * child)
+ {
+ const std::string& name = child->getNameString();
+
+ if( !hasSuffix(name, GEO) )
+ return Group::valueChanged(child);
+
+ GeoNodes::iterator it_geo_node = _geo_nodes.find(child);
+ if( it_geo_node == _geo_nodes.end() )
+ LOG_GEO_RET("geo node not found!")
+ GeoNodePair* geo_node = it_geo_node->second.get();
+
+ geo_node->setDirty();
+
+ if( geo_node->getStatus() & GeoNodePair::INCOMPLETE )
+ {
+ // Detect lat, lon tuples...
+ GeoCoord coord = parseGeoCoord(child->getStringValue());
+ int index_other = -1;
+
+ switch( coord.type )
+ {
+ case GeoCoord::LATITUDE:
+ index_other = child->getIndex() + 1;
+ geo_node->setNodeLat(child);
+ break;
+ case GeoCoord::LONGITUDE:
+ index_other = child->getIndex() - 1;
+ geo_node->setNodeLon(child);
+ break;
+ default:
+ LOG_GEO_RET("Invalid geo coord")
+ }
+
+ SGPropertyNode *other = child->getParent()->getChild(name, index_other);
+ if( !other )
+ return;
+
+ GeoCoord coord_other = parseGeoCoord(other->getStringValue());
+ if( coord_other.type == GeoCoord::INVALID
+ || coord_other.type == coord.type )
+ return;
+
+ GeoNodes::iterator it_geo_node_other = _geo_nodes.find(other);
+ if( it_geo_node_other == _geo_nodes.end() )
+ LOG_GEO_RET("other geo node not found!")
+ GeoNodePair* geo_node_other = it_geo_node_other->second.get();
+
+ // Let use both nodes use the same GeoNodePair instance
+ if( geo_node_other != geo_node )
+ it_geo_node_other->second = it_geo_node->second;
+
+ if( coord_other.type == GeoCoord::LATITUDE )
+ geo_node->setNodeLat(other);
+ else
+ geo_node->setNodeLon(other);
+
+ // Set name for resulting screen coordinate nodes
+ geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
+ }
+ }
+
+ //----------------------------------------------------------------------------
+ void Map::childChanged(SGPropertyNode * child)
+ {
+ if( child->getNameString() == "ref-lat"
+ || child->getNameString() == "ref-lon" )
+ projection.setWorldPosition( _node->getDoubleValue("ref-lat"),
+ _node->getDoubleValue("ref-lon") );
+ else if( child->getNameString() == "hdg" )
+ projection.setOrientation(child->getFloatValue());
+ else if( child->getNameString() == "range" )
+ projection.setRange(child->getDoubleValue());
+ else
+ return;
+
+ _projection_dirty = true;
+ }
+
+ //----------------------------------------------------------------------------
+ Map::GeoCoord Map::parseGeoCoord(const std::string& val) const
+ {
+ GeoCoord coord;
+ if( val.length() < 2 )
+ return coord;
+
+ if( val[0] == 'N' || val[0] == 'S' )
+ coord.type = GeoCoord::LATITUDE;
+ else if( val[0] == 'E' || val[0] == 'W' )
+ coord.type = GeoCoord::LONGITUDE;
+ else
+ return coord;
+
+ char* end;
+ coord.value = strtod(&val[1], &end);
+
+ if( end != &val[val.length()] )
+ {
+ coord.type = GeoCoord::INVALID;
+ return coord;
+ }
+
+ if( val[0] == 'S' || val[0] == 'W' )
+ coord.value *= -1;
+
+ return coord;
+ }
+
+ //----------------------------------------------------------------------------
+ bool Map::hasSuffix(const std::string& str, const std::string& suffix) const
+ {
+ if( suffix.length() > str.length() )
+ return false;
+
+ return ( str.compare( str.length() - suffix.length(),
+ suffix.length(),
+ suffix ) == 0 );
+ }
+
+} // namespace canvas
--- /dev/null
+// A group of 2D canvas elements which get automatically transformed according
+// to the map parameters.
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef CANVAS_MAP_HXX_
+#define CANVAS_MAP_HXX_
+
+#include "group.hxx"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/unordered_map.hpp>
+
+namespace canvas
+{
+ class GeoNodePair;
+ class Map:
+ public Group
+ {
+ public:
+ Map(SGPropertyNode_ptr node);
+ virtual ~Map();
+
+ virtual void update(double dt);
+
+ virtual void childAdded( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void childRemoved( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void valueChanged(SGPropertyNode * child);
+
+ protected:
+
+ virtual void childChanged(SGPropertyNode * child);
+
+ typedef boost::unordered_map< SGPropertyNode*,
+ boost::shared_ptr<GeoNodePair>
+ > GeoNodes;
+ GeoNodes _geo_nodes;
+ bool _projection_dirty;
+
+ struct GeoCoord
+ {
+ GeoCoord():
+ type(INVALID)
+ {}
+ enum
+ {
+ INVALID,
+ LATITUDE,
+ LONGITUDE
+ } type;
+ double value;
+ };
+
+ GeoCoord parseGeoCoord(const std::string& val) const;
+
+ bool hasSuffix(const std::string& str, const std::string& suffix) const;
+ };
+
+} // namespace canvas
+
+#endif /* CANVAS_MAP_HXX_ */
--- /dev/null
+/*
+ * geo_node_pair.hxx
+ *
+ * Created on: 11.07.2012
+ * Author: tom
+ */
+
+#ifndef CANVAS_GEO_NODE_PAIR_HXX_
+#define CANVAS_GEO_NODE_PAIR_HXX_
+
+namespace canvas
+{
+ class GeoNodePair
+ {
+ public:
+ enum StatusFlags
+ {
+ LAT_MISSING = 1,
+ LON_MISSING = LAT_MISSING << 1,
+ INCOMPLETE = LAT_MISSING | LON_MISSING,
+ DIRTY = LON_MISSING << 1
+ };
+
+ GeoNodePair():
+ _status(INCOMPLETE),
+ _node_lat(0),
+ _node_lon(0)
+ {}
+
+ uint8_t getStatus() const
+ {
+ return _status;
+ }
+
+ void setDirty(bool flag = true)
+ {
+ if( flag )
+ _status |= DIRTY;
+ else
+ _status &= ~DIRTY;
+ }
+
+ bool isDirty() const
+ {
+ return _status & DIRTY;
+ }
+
+ bool isComplete() const
+ {
+ return !(_status & INCOMPLETE);
+ }
+
+ void setNodeLat(SGPropertyNode* node)
+ {
+ _node_lat = node;
+ _status &= ~LAT_MISSING;
+
+ if( node == _node_lon )
+ {
+ _node_lon = 0;
+ _status |= LON_MISSING;
+ }
+ }
+
+ void setNodeLon(SGPropertyNode* node)
+ {
+ _node_lon = node;
+ _status &= ~LON_MISSING;
+
+ if( node == _node_lat )
+ {
+ _node_lat = 0;
+ _status |= LAT_MISSING;
+ }
+ }
+
+ const char* getLat() const
+ {
+ return _node_lat ? _node_lat->getStringValue() : "";
+ }
+
+ const char* getLon() const
+ {
+ return _node_lon ? _node_lon->getStringValue() : "";
+ }
+
+ void setTargetName(const std::string& name)
+ {
+ _target_name = name;
+ }
+
+ void setScreenPos(float x, float y)
+ {
+ assert( isComplete() );
+ SGPropertyNode *parent = _node_lat->getParent();
+ parent->getChild(_target_name, _node_lat->getIndex(), true)
+ ->setDoubleValue(x);
+ parent->getChild(_target_name, _node_lon->getIndex(), true)
+ ->setDoubleValue(y);
+ }
+
+ void print()
+ {
+ std::cout << "lat=" << (_node_lat ? _node_lat->getPath() : "")
+ << ", lon=" << (_node_lon ? _node_lon->getPath() : "")
+ << std::endl;
+ }
+
+ private:
+
+ uint8_t _status;
+ SGPropertyNode *_node_lat,
+ *_node_lon;
+ std::string _target_name;
+
+ };
+
+} // namespace canvas
+
+#endif /* CANVAS_GEO_NODE_PAIR_HXX_ */
--- /dev/null
+/*
+ * projection.hxx
+ *
+ * Created on: 12.07.2012
+ * Author: tom
+ */
+
+#ifndef CANVAS_MAP_PROJECTION_HXX_
+#define CANVAS_MAP_PROJECTION_HXX_
+
+const double DEG2RAD = M_PI / 180.0;
+
+namespace canvas
+{
+
+ /**
+ * Base class for all projections
+ */
+ class Projection
+ {
+ public:
+ struct ScreenPosition
+ {
+ ScreenPosition() {}
+
+ ScreenPosition(double x, double y):
+ x(x),
+ y(y)
+ {}
+
+ double x, y;
+ };
+
+ virtual ~Projection() {}
+
+ void setScreenRange(double range)
+ {
+ _screen_range = range;
+ }
+
+ virtual ScreenPosition worldToScreen(double x, double y) = 0;
+
+ protected:
+
+ double _screen_range;
+ };
+
+ /**
+ * Base class for horizontal projections
+ */
+ class HorizontalProjection:
+ public Projection
+ {
+ public:
+
+ HorizontalProjection():
+ _cos_rot(1),
+ _sin_rot(0),
+ _range(5)
+ {
+ setScreenRange(200);
+ }
+
+ /**
+ * Set world position of center point used for the projection
+ */
+ void setWorldPosition(double lat, double lon)
+ {
+ _ref_lat = lat * DEG2RAD;
+ _ref_lon = lon * DEG2RAD;
+ }
+
+ /**
+ * Set up heading
+ */
+ void setOrientation(float hdg)
+ {
+ hdg *= DEG2RAD;
+ _sin_rot = sin(hdg);
+ _cos_rot = cos(hdg);
+ }
+
+ void setRange(double range)
+ {
+ _range = range;
+ }
+
+ /**
+ * Transform given world position to screen position
+ *
+ * @param lat Latitude in degrees
+ * @param lon Longitude in degrees
+ */
+ ScreenPosition worldToScreen(double lat, double lon)
+ {
+ lat *= DEG2RAD;
+ lon *= DEG2RAD;
+ ScreenPosition pos = project(lat, lon);
+ double scale = _screen_range / _range;
+ pos.x *= scale;
+ pos.y *= scale;
+ return ScreenPosition
+ (
+ _cos_rot * pos.x - _sin_rot * pos.y,
+ -_sin_rot * pos.x - _cos_rot * pos.y
+ );
+ }
+
+ protected:
+
+ /**
+ * Project given geographic world position to screen space
+ *
+ * @param lat Latitude in radians
+ * @param lon Longitude in radians
+ */
+ virtual ScreenPosition project(double lat, double lon) const = 0;
+
+ double _ref_lat,
+ _ref_lon,
+ _cos_rot,
+ _sin_rot,
+ _range;
+ };
+
+ /**
+ * Sanson-Flamsteed projection, relative to the projection center
+ */
+ class SansonFlamsteedProjection:
+ public HorizontalProjection
+ {
+ protected:
+
+ virtual ScreenPosition project(double lat, double lon) const
+ {
+ double d_lat = lat - _ref_lat,
+ d_lon = lon - _ref_lon;
+ double r = getEarthRadius(lat);
+
+ ScreenPosition pos;
+
+ pos.x = r * cos(lat) * d_lon;
+ pos.y = r * d_lat;
+
+ return pos;
+ }
+
+ /**
+ * Returns Earth radius at a given latitude (Ellipsoide equation with two
+ * equal axis)
+ */
+ float getEarthRadius(float lat) const
+ {
+ const float rec = 6378137.f / 1852; // earth radius, equator (?)
+ const float rpol = 6356752.314f / 1852; // earth radius, polar (?)
+
+ double a = cos(lat) / rec;
+ double b = sin(lat) / rpol;
+ return 1.0f / sqrt( a * a + b * b );
+ }
+ };
+
+} // namespace canvas
+
+#endif /* CANVAS_MAP_PROJECTION_HXX_ */
_paint_fill(VG_INVALID_HANDLE),
_attributes_dirty(~0),
_stroke_width(1),
+ _stroke_linecap(VG_CAP_BUTT),
_fill(false)
{
setSupportsDisplayList(false);
_attributes_dirty |= FILL_COLOR;
}
+ /**
+ * Set stroke-linecap
+ *
+ * @see http://www.w3.org/TR/SVG/painting.html#StrokeLinecapProperty
+ */
+ void setStrokeLinecap(const std::string& linecap)
+ {
+ if( linecap == "round" )
+ _stroke_linecap = VG_CAP_ROUND;
+ else if( linecap == "square" )
+ _stroke_linecap = VG_CAP_SQUARE;
+ else
+ _stroke_linecap = VG_CAP_BUTT;
+ }
+
/**
* Draw callback
*/
vgSetPaint(_paint, VG_STROKE_PATH);
vgSetf(VG_STROKE_LINE_WIDTH, _stroke_width);
+ vgSeti(VG_STROKE_CAP_STYLE, _stroke_linecap);
vgSetfv( VG_STROKE_DASH_PATTERN,
_stroke_dash.size(),
_stroke_dash.empty() ? 0 : &_stroke_dash[0] );
VGfloat _stroke_color[4];
VGfloat _stroke_width;
std::vector<VGfloat> _stroke_dash;
+ VGCapStyle _stroke_linecap;
bool _fill;
VGfloat _fill_color[4];
else if( child->getNameString() == "stroke-width"
|| child->getNameString() == "stroke-dasharray" )
_attributes_dirty |= STROKE;
+ else if( child->getNameString() == "stroke-linecap" )
+ _path->setStrokeLinecap( child->getStringValue() );
else if( child->getNameString() == "fill" )
_path->enableFill( child->getBoolValue() );
}
namespace canvas
{
+ class Text::TextOSG:
+ public osgText::Text
+ {
+ public:
+ osg::Vec2 handleHit(float x, float y);
+ };
+
+ //----------------------------------------------------------------------------
+ osg::Vec2 Text::TextOSG::handleHit(float x, float y)
+ {
+ float line_height = _characterHeight + _lineSpacing;
+
+ // TODO check with align other than TOP
+ float first_line_y = -0.5 * _lineSpacing;//_offset.y() - _characterHeight;
+ size_t line = std::max<int>(0, (y - first_line_y) / line_height);
+
+ if( _textureGlyphQuadMap.empty() )
+ return osg::Vec2(-1, -1);
+
+ // TODO check when it can be larger
+ assert( _textureGlyphQuadMap.size() == 1 );
+
+ const GlyphQuads& glyphquad = _textureGlyphQuadMap.begin()->second;
+ const GlyphQuads::Glyphs& glyphs = glyphquad._glyphs;
+ const GlyphQuads::Coords2& coords = glyphquad._coords;
+ const GlyphQuads::LineNumbers& line_numbers = glyphquad._lineNumbers;
+
+ const float HIT_FRACTION = 0.6;
+ const float character_width = getCharacterHeight()
+ * getCharacterAspectRatio();
+
+ y = (line + 0.5) * line_height;
+
+ bool line_found = false;
+ for(size_t i = 0; i < line_numbers.size(); ++i)
+ {
+ if( line_numbers[i] != line )
+ {
+ if( !line_found )
+ {
+ if( line_numbers[i] < line )
+ // Wait for the correct line...
+ continue;
+
+ // We have already passed the correct line -> It's empty...
+ return osg::Vec2(0, y);
+ }
+
+ // Next line and not returned -> not before any character
+ // -> return position after last character of line
+ return osg::Vec2(coords[(i - 1) * 4 + 2].x(), y);
+ }
+
+ line_found = true;
+
+ // Get threshold for mouse x position for setting cursor before or after
+ // current character
+ float threshold = coords[i * 4].x()
+ + HIT_FRACTION * glyphs[i]->getHorizontalAdvance()
+ * character_width;
+
+ if( x <= threshold )
+ {
+ if( i == 0 || line_numbers[i - 1] != line )
+ // first character of line
+ x = coords[i * 4].x();
+ else if( coords[(i - 1) * 4].x() == coords[(i - 1) * 4 + 2].x() )
+ // If previous character width is zero set to begin of next character
+ // (Happens eg. with spaces)
+ x = coords[i * 4].x();
+ else
+ // position at center between characters
+ x = 0.5 * (coords[(i - 1) * 4 + 2].x() + coords[i * 4].x());
+
+ return osg::Vec2(x, y);
+ }
+ }
+
+ // Nothing found -> return position after last character
+ return osg::Vec2
+ (
+ coords.back().x(),
+ (_lineCount - 0.5) * line_height
+ );
+ }
//----------------------------------------------------------------------------
Text::Text(SGPropertyNode_ptr node):
Element(node, COLOR | COLOR_FILL | BOUNDING_BOX),
- _text( new osgText::Text ),
+ _text( new Text::TextOSG() ),
_font_size( 0 ),
_font_aspect( 0 )
{
_font_size = getChildDefault<float>(_node, "character-size", 32);
_font_aspect = getChildDefault<float>(_node, "character-aspect-ratio", 1);
-
- _node->tie
- (
- "alignment",
- SGRawValueMethods<Text, const char*>
- (
- *this,
- &Text::getAlignment,
- &Text::setAlignment
- )
- );
- _node->tie
- (
- "padding",
- SGRawValueMethods<osgText::Text, float>
- (
- *_text.get(),
- &osgText::Text::getBoundingBoxMargin,
- &osgText::Text::setBoundingBoxMargin
- )
- );
- typedef SGRawValueMethods<osgText::Text, int> TextIntMethods;
- _node->tie
- (
- "draw-mode",
- // TEXT = 1 default
- // BOUNDINGBOX = 2
- // FILLEDBOUNDINGBOX = 4
- // ALIGNMENT = 8
- TextIntMethods
- (
- *_text.get(),
- (TextIntMethods::getter_t)&osgText::Text::getDrawMode,
- (TextIntMethods::setter_t)&osgText::Text::setDrawMode
- )
- );
}
//----------------------------------------------------------------------------
Text::~Text()
{
- if( _node )
- {
- _node->untie("alignment");
- _node->untie("padding");
- _node->untie("draw-mode");
- }
- _node = 0;
+
}
//----------------------------------------------------------------------------
#include "text-alignment.hxx"
#undef ENUM_MAPPING
else
+ {
+ if( !align_string.empty() )
+ SG_LOG
+ (
+ SG_GENERAL,
+ SG_WARN,
+ "canvas::Text: unknown alignment '" << align_string << "'"
+ );
_text->setAlignment(osgText::Text::LEFT_BASE_LINE);
+ }
}
//----------------------------------------------------------------------------
+#if 0
const char* Text::getAlignment() const
{
switch( _text->getAlignment() )
return "unknown";
}
}
-
+#endif
//----------------------------------------------------------------------------
void Text::childChanged(SGPropertyNode* child)
{
- if( _font_size == child || _font_aspect == child )
+ const std::string& name = child->getNameString();
+
+ if( name == "hit-y" )
+ handleHit
+ (
+ _node->getFloatValue("hit-x"),
+ _node->getFloatValue("hit-y")
+ );
+ else if( _font_size == child || _font_aspect == child )
_attributes_dirty |= FONT_SIZE;
- else if( child->getNameString() == "text" )
- _text->setText( child->getStringValue() );
- else if( child->getNameString() == "font" )
+ else if( name == "text" )
+ _text->setText
+ (
+ osgText::String( child->getStringValue(),
+ osgText::String::ENCODING_UTF8 )
+ );
+ else if( name == "padding" )
+ _text->setBoundingBoxMargin( child->getFloatValue() );
+ else if( name == "draw-mode" )
+ // TEXT = 1 default
+ // BOUNDINGBOX = 2
+ // FILLEDBOUNDINGBOX = 4
+ // ALIGNMENT = 8
+ _text->setDrawMode( child->getIntValue() );
+ else if( name == "max-width" )
+ _text->setMaximumWidth( child->getFloatValue() );
+ else if( name == "font" )
setFont( child->getStringValue() );
+ else if( name == "alignment" )
+ setAlignment( child->getStringValue() );
}
//----------------------------------------------------------------------------
_text->setBoundingBoxColor(color);
}
+ //----------------------------------------------------------------------------
+ void Text::handleHit(float x, float y)
+ {
+ const osg::Vec2& pos = _text->handleHit(x, y);
+ _node->setFloatValue("cursor-x", pos.x());
+ _node->setFloatValue("cursor-y", pos.y());
+ }
+
//----------------------------------------------------------------------------
Text::font_ptr Text::getFont(const std::string& name)
{
{
public:
Text(SGPropertyNode_ptr node);
- virtual ~Text();
+ ~Text();
virtual void update(double dt);
void setFont(const char* name);
-
void setAlignment(const char* align);
- const char* getAlignment() const;
protected:
FONT_SIZE = LAST_ATTRIBUTE << 1, // Font size and aspect ration
};
- osg::ref_ptr<osgText::Text> _text;
+ class TextOSG;
+ osg::ref_ptr<TextOSG> _text;
SGPropertyNode_ptr _font_size,
_font_aspect;
virtual void colorChanged(const osg::Vec4& color);
virtual void colorFillChanged(const osg::Vec4& color);
+ void handleHit(float x, float y);
+
typedef osg::ref_ptr<osgText::Font> font_ptr;
static font_ptr getFont(const std::string& name);
};
--- /dev/null
+// Canvas gui/dialog manager
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#include "gui_mgr.hxx"
+#include <Canvas/window.hxx>
+#include <Canvas/canvas.hxx>
+
+#include <Main/globals.hxx>
+#include <Viewer/CameraGroup.hxx>
+#include <Viewer/renderer.hxx>
+
+#include <osgViewer/Viewer>
+#include <osgGA/GUIEventHandler>
+
+#include <boost/bind.hpp>
+
+/**
+ * Event handler
+ */
+class GUIEventHandler:
+ public osgGA::GUIEventHandler
+{
+ public:
+ GUIEventHandler(GUIMgr* gui_mgr):
+ _gui_mgr( gui_mgr )
+ {}
+
+ bool handle( const osgGA::GUIEventAdapter& ea,
+ osgGA::GUIActionAdapter& aa,
+ osg::Object*,
+ osg::NodeVisitor* )
+ {
+ return _gui_mgr->handleEvent(ea);
+ }
+
+ protected:
+ GUIMgr *_gui_mgr;
+};
+
+/**
+ * Track a canvas placement on a window
+ */
+class WindowPlacement:
+ public canvas::Placement
+{
+ public:
+ WindowPlacement( canvas::WindowPtr window,
+ CanvasPtr canvas ):
+ _window(window),
+ _canvas(canvas)
+ {}
+
+ /**
+ * Remove placement from window
+ */
+ virtual ~WindowPlacement()
+ {
+ canvas::WindowPtr window = _window.lock();
+ CanvasPtr canvas = _canvas.lock();
+
+ if( window && canvas && canvas == window->getCanvas().lock() )
+ window->setCanvas( CanvasPtr() );
+ }
+
+ private:
+ canvas::WindowWeakPtr _window;
+ CanvasWeakPtr _canvas;
+};
+
+//------------------------------------------------------------------------------
+typedef boost::shared_ptr<canvas::Window> WindowPtr;
+WindowPtr windowFactory(SGPropertyNode* node)
+{
+ return WindowPtr(new canvas::Window(node));
+}
+
+//------------------------------------------------------------------------------
+GUIMgr::GUIMgr():
+ PropertyBasedMgr("/sim/gui/canvas", "window", &windowFactory),
+ _event_handler( new GUIEventHandler(this) ),
+ _transform( new osg::MatrixTransform ),
+ _geode_windows( new osg::Geode ),
+ _width(_props, "size[0]"),
+ _height(_props, "size[1]"),
+ _last_push(-1)
+{
+ _width = _height = -1;
+
+ osg::Camera* camera =
+ flightgear::getGUICamera( flightgear::CameraGroup::getDefault() );
+ assert(camera);
+
+ osg::Viewport* vp = camera->getViewport();
+ handleResize(vp->x(), vp->y(), vp->width(), vp->height());
+
+ _transform->addChild(_geode_windows);
+ camera->addChild(_transform);
+
+ Canvas::addPlacementFactory
+ (
+ "window",
+ boost::bind(&GUIMgr::addPlacement, this, _1, _2)
+ );
+}
+
+//------------------------------------------------------------------------------
+void GUIMgr::init()
+{
+ PropertyBasedMgr::init();
+
+ globals->get_renderer()
+ ->getViewer()
+ ->addEventHandler( _event_handler );
+}
+
+//------------------------------------------------------------------------------
+void GUIMgr::shutdown()
+{
+ PropertyBasedMgr::shutdown();
+
+ globals->get_renderer()
+ ->getViewer()
+ ->removeEventHandler( _event_handler );
+}
+
+//------------------------------------------------------------------------------
+void GUIMgr::elementCreated(PropertyBasedElementPtr element)
+{
+ _geode_windows->addDrawable
+ (
+ static_cast<canvas::Window*>(element.get())->getDrawable()
+ );
+}
+
+//------------------------------------------------------------------------------
+bool GUIMgr::handleEvent(const osgGA::GUIEventAdapter& ea)
+{
+ switch( ea.getEventType() )
+ {
+ case osgGA::GUIEventAdapter::PUSH:
+ case osgGA::GUIEventAdapter::RELEASE:
+// case osgGA::GUIEventAdapter::DOUBLECLICK:
+// // DOUBLECLICK doesn't seem to be triggered...
+ case osgGA::GUIEventAdapter::DRAG:
+ case osgGA::GUIEventAdapter::MOVE:
+ case osgGA::GUIEventAdapter::SCROLL:
+ return handleMouse(ea);
+// case osgGA::GUIEventAdapter::MOVE:
+// std::cout << "MOVE" << std::endl;
+// break;
+ case osgGA::GUIEventAdapter::RESIZE:
+ handleResize( ea.getWindowX(),
+ ea.getWindowY(),
+ ea.getWindowWidth(),
+ ea.getWindowHeight() );
+ return true;
+ default:
+ return false;
+ }
+}
+
+//------------------------------------------------------------------------------
+canvas::WindowPtr GUIMgr::getWindow(size_t i)
+{
+ return boost::shared_static_cast<canvas::Window>(_elements[i]);
+}
+
+//------------------------------------------------------------------------------
+canvas::Placements GUIMgr::addPlacement( const SGPropertyNode* node,
+ CanvasPtr canvas )
+{
+ int placement_index = node->getIntValue("index", -1);
+
+ canvas::Placements placements;
+ for( size_t i = 0; i < _elements.size(); ++i )
+ {
+ if( placement_index > 0 && static_cast<int>(i) != placement_index )
+ continue;
+
+ canvas::WindowPtr window = getWindow(i);
+ if( !window )
+ continue;
+
+ window->setCanvas(canvas);
+ placements.push_back(
+ canvas::PlacementPtr(new WindowPlacement(window, canvas))
+ );
+ }
+ return placements;
+}
+
+//------------------------------------------------------------------------------
+bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
+{
+ canvas::MouseEvent event( ea.getEventType() );
+
+ event.x = 0.5 * (ea.getXnormalized() + 1) * _width + 0.5;
+ event.y = 0.5 * (ea.getYnormalized() + 1) * _height + 0.5;
+ if( ea.getMouseYOrientation()
+ != osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS )
+ event.y = _height - event.y;
+
+ event.button = ea.getButton();
+ event.state = ea.getButtonMask();
+ event.mod = ea.getModKeyMask();
+ event.scroll = ea.getScrollingMotion();
+
+ int window_at_cursor = -1;
+ for( size_t i = 0; i < _elements.size(); ++i )
+ {
+ if( _elements[i]
+ && getWindow(i)->getRegion().contains(event.x, event.y) )
+ {
+ window_at_cursor = i;
+ break;
+ }
+ }
+
+ int target_window = window_at_cursor;
+ switch( ea.getEventType() )
+ {
+ case osgGA::GUIEventAdapter::PUSH:
+ _last_push = window_at_cursor;
+ break;
+ case osgGA::GUIEventAdapter::SCROLL:
+ case osgGA::GUIEventAdapter::MOVE:
+ break;
+
+ case osgGA::GUIEventAdapter::RELEASE:
+ if( _last_push < 0 )
+ return false;
+
+ target_window = _last_push;
+ _last_push = -1;
+ break;
+
+ case osgGA::GUIEventAdapter::DRAG:
+ target_window = _last_push;
+ break;
+
+ default:
+ return false;
+ }
+
+ if( target_window >= 0 )
+ {
+ canvas::WindowPtr window = getWindow(target_window);
+
+ event.dx = event.x - _last_x;
+ event.dy = event.y - _last_y;
+
+ _last_x = event.x;
+ _last_y = event.y;
+
+ // Let the event position be always relative to the top left window corner
+ event.x -= window->getRegion().x();
+ event.y -= window->getRegion().y();
+
+ return window->handleMouseEvent(event);
+ }
+ else
+ return false;
+}
+
+//------------------------------------------------------------------------------
+void GUIMgr::handleResize(int x, int y, int width, int height)
+{
+ if( _width == width && _height == height )
+ return;
+
+ _width = width;
+ _height = height;
+
+ // Origin should be at top left corner, therefore we need to mirror the y-axis
+ _transform->setMatrix(osg::Matrix(
+ 1, 0, 0, 0,
+ 0, -1, 0, 0,
+ 0, 0, 1, 0,
+ 0, _height, 0, 1
+ ));
+}
--- /dev/null
+// Canvas gui/dialog manager
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef CANVAS_GUI_MGR_HXX_
+#define CANVAS_GUI_MGR_HXX_
+
+#include "property_based_mgr.hxx"
+#include <Canvas/canvas_fwd.hpp>
+#include <Canvas/placement.hxx>
+
+#include <simgear/props/propertyObject.hxx>
+
+#include <osg/ref_ptr>
+#include <osg/Geode>
+#include <osg/MatrixTransform>
+
+namespace osgGA
+{
+ class GUIEventAdapter;
+}
+
+class GUIEventHandler;
+class GUIMgr:
+ public PropertyBasedMgr
+{
+ public:
+ GUIMgr();
+
+ virtual void init();
+ virtual void shutdown();
+
+ virtual void elementCreated(PropertyBasedElementPtr element);
+
+ bool handleEvent(const osgGA::GUIEventAdapter& ea);
+
+ protected:
+ osg::ref_ptr<GUIEventHandler> _event_handler;
+ osg::ref_ptr<osg::MatrixTransform> _transform;
+ osg::ref_ptr<osg::Geode> _geode_windows;
+
+ simgear::PropertyObject<int> _width,
+ _height;
+
+ int _last_push,
+ _last_x,
+ _last_y;
+
+ canvas::WindowPtr getWindow(size_t i);
+ canvas::Placements addPlacement( const SGPropertyNode*,
+ CanvasPtr canvas );
+
+ bool handleMouse(const osgGA::GUIEventAdapter& ea);
+ void handleResize(int x, int y, int width, int height);
+};
+
+#endif /* CANVAS_GUI_MGR_HXX_ */
--- /dev/null
+// Base class for canvas placements
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#include "placement.hxx"
+
+namespace canvas
+{
+
+ //----------------------------------------------------------------------------
+ Placement::Placement()
+ {
+
+ }
+
+ //----------------------------------------------------------------------------
+ Placement::~Placement()
+ {
+
+ }
+
+} // namespace canvas
--- /dev/null
+// Base class for canvas placements
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef CANVAS_PLACEMENT_HXX_
+#define CANVAS_PLACEMENT_HXX_
+
+namespace canvas
+{
+
+ class Placement
+ {
+ public:
+ Placement();
+ virtual ~Placement() = 0;
+
+ private:
+ Placement(const Placement&) /* = delete */;
+ Placement& operator=(const Placement&) /* = delete */;
+ };
+
+} // namespace canvas
+
+#endif /* CANVAS_PLACEMENT_HXX_ */
--- /dev/null
+// Base class for elements of property controlled subsystems
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#include "property_based_element.hxx"
+
+//------------------------------------------------------------------------------
+PropertyBasedElement::PropertyBasedElement(SGPropertyNode* node):
+ _node(node)
+{
+ _node->addChangeListener(this);
+}
+
+//------------------------------------------------------------------------------
+PropertyBasedElement::~PropertyBasedElement()
+{
+ _node->removeChangeListener(this);
+}
--- /dev/null
+// Base class for elements of property controlled subsystems
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef PROPERTY_BASED_ELEMENT_HXX_
+#define PROPERTY_BASED_ELEMENT_HXX_
+
+#include <Canvas/canvas_fwd.hpp>
+#include <simgear/props/props.hxx>
+
+/**
+ * Base class for a property controlled element
+ */
+class PropertyBasedElement:
+ public SGPropertyChangeListener
+{
+ public:
+ PropertyBasedElement(SGPropertyNode* node);
+ virtual ~PropertyBasedElement();
+
+ virtual void update(double delta_time_sec) = 0;
+
+ protected:
+
+ friend class PropertyBasedMgr;
+
+ SGPropertyNode_ptr _node;
+ PropertyBasedElementWeakPtr _self;
+};
+
+
+#endif /* PROPERTY_BASED_ELEMENT_HXX_ */
--- /dev/null
+// Base class for all property controlled subsystems
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#include "property_based_mgr.hxx"
+#include "property_helper.hxx"
+#include <Main/fg_props.hxx>
+
+#include <stdexcept>
+#include <string>
+
+//------------------------------------------------------------------------------
+void PropertyBasedMgr::init()
+{
+ _props->addChangeListener(this);
+ canvas::triggerChangeRecursive(_props);
+}
+
+//------------------------------------------------------------------------------
+void PropertyBasedMgr::shutdown()
+{
+ _props->removeChangeListener(this);
+}
+
+//------------------------------------------------------------------------------
+void PropertyBasedMgr::update(double delta_time_sec)
+{
+ for( size_t i = 0; i < _elements.size(); ++i )
+ if( _elements[i] )
+ _elements[i]->update(delta_time_sec);
+}
+
+//------------------------------------------------------------------------------
+void PropertyBasedMgr::childAdded( SGPropertyNode * parent,
+ SGPropertyNode * child )
+{
+ if( parent != _props || child->getNameString() != _name_elements )
+ return;
+
+ size_t index = child->getIndex();
+
+ if( index >= _elements.size() )
+ {
+ if( index > _elements.size() )
+ SG_LOG
+ (
+ SG_GENERAL,
+ SG_WARN,
+ "Skipping unused " << _name_elements << " slot(s)!"
+ );
+
+ _elements.resize(index + 1);
+ }
+ else if( _elements[index] )
+ SG_LOG
+ (
+ SG_GENERAL,
+ SG_WARN,
+ _name_elements << "[" << index << "] already exists!"
+ );
+
+ PropertyBasedElementPtr el = _element_factory(child);
+ el->_self = el;
+ _elements[index] = el;
+ elementCreated( el );
+}
+
+//------------------------------------------------------------------------------
+void PropertyBasedMgr::childRemoved( SGPropertyNode * parent,
+ SGPropertyNode * child )
+{
+ if( parent != _props || child->getNameString() != _name_elements )
+ return;
+
+ size_t index = child->getIndex();
+
+ if( index >= _elements.size() )
+ SG_LOG
+ (
+ SG_GENERAL,
+ SG_WARN,
+ "can't removed unknown " << _name_elements << "[" << index << "]!"
+ );
+ else
+ // remove the element...
+ _elements[index].reset();
+}
+
+//------------------------------------------------------------------------------
+PropertyBasedMgr::PropertyBasedMgr( const std::string& path_root,
+ const std::string& name_elements,
+ ElementFactory element_factory ):
+ _props( fgGetNode(path_root, true) ),
+ _name_elements( name_elements ),
+ _element_factory( element_factory )
+{
+
+}
+
+//------------------------------------------------------------------------------
+PropertyBasedMgr::~PropertyBasedMgr()
+{
+
+}
--- /dev/null
+// Base class for all property controlled subsystems
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef PROPERTY_BASED_MGR_HXX_
+#define PROPERTY_BASED_MGR_HXX_
+
+#include "property_based_element.hxx"
+#include <simgear/structure/subsystem_mgr.hxx>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <vector>
+
+class PropertyBasedMgr:
+ public SGSubsystem,
+ public SGPropertyChangeListener
+{
+ public:
+ virtual void init();
+ virtual void shutdown();
+
+ virtual void update (double delta_time_sec);
+
+ virtual void childAdded( SGPropertyNode * parent,
+ SGPropertyNode * child );
+ virtual void childRemoved( SGPropertyNode * parent,
+ SGPropertyNode * child );
+
+ virtual void elementCreated(PropertyBasedElementPtr element) {}
+
+ protected:
+
+ typedef boost::function<PropertyBasedElementPtr(SGPropertyNode*)>
+ ElementFactory;
+
+ /** Branch in the property tree for this property managed subsystem */
+ SGPropertyNode* _props;
+
+ /** Property name of managed elements */
+ const std::string _name_elements;
+
+ /** The actually managed elements */
+ std::vector<PropertyBasedElementPtr> _elements;
+
+ /** Function object which creates a new element */
+ ElementFactory _element_factory;
+
+ /**
+ * @param path_root Path to property branch used for controlling this
+ * subsystem
+ * @param name_elements The name of the nodes for the managed elements
+ */
+ PropertyBasedMgr( const std::string& path_root,
+ const std::string& name_elements,
+ ElementFactory element_factory );
+ virtual ~PropertyBasedMgr() = 0;
+
+};
+
+#endif /* PROPERTY_BASED_MGR_HXX_ */
for( size_t i = 0; i < num_channels; ++i )
nodes.push_back( getChildDefault(color, channels[i], def[i]) );
}
+
+ //----------------------------------------------------------------------------
+ void triggerChangeRecursive(SGPropertyNode* node)
+ {
+ node->getParent()->fireChildAdded(node);
+
+ if( node->nChildren() == 0 && node->getType() != simgear::props::NONE )
+ return node->fireValueChanged();
+
+ for( int i = 0; i < node->nChildren(); ++i )
+ triggerChangeRecursive( node->getChild(i) );
+ }
}
std::vector<SGPropertyNode_ptr>& nodes,
const osg::Vec4& def = osg::Vec4(0,0,0,1) );
+ /**
+ * Trigger a childAdded and valueChanged event for every child of node
+ * (Unlimited depth) and node itself.
+ */
+ void triggerChangeRecursive(SGPropertyNode* node);
+
} // namespace canvas
#endif /* PROPERTY_HELPER_HXX_ */
--- /dev/null
+// Class representing a rectangular region
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef CANVAS_RECT_HXX_
+#define CANVAS_RECT_HXX_
+
+#include <osg/Vec2>
+
+namespace canvas
+{
+ template<typename T>
+ class Rect
+ {
+ public:
+ Rect() {}
+
+ Rect(T x, T y, T w, T h):
+ _x1(x),
+ _x2(x + w),
+ _y1(y),
+ _y2(y + h)
+ {}
+
+ void set(T x, T y, T w, T h)
+ {
+ _x1 = x;
+ _x2 = x + w;
+ _y1 = y;
+ _y2 = y + h;
+ }
+
+ T x() const { return _x1; }
+ T y() const { return _y1; }
+ T width() const { return _x2 - _x1; }
+ T height() const { return _y2 - _y1; }
+
+ T l() const { return _x1; }
+ T r() const { return _x2; }
+ T t() const { return _y1; }
+ T b() const { return _y2; }
+
+ bool contains(T x, T y) const
+ {
+ return _x1 <= x && x <= _x2
+ && _y1 <= y && y <= _y2;
+ }
+
+ private:
+ T _x1, _x2, _y1, _y2;
+ };
+} // namespace canvas
+
+#endif /* CANVAS_RECT_HXX_ */
--- /dev/null
+// Window for placing a Canvas onto it (for dialogs, menus, etc.)
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#include "window.hxx"
+#include <Canvas/canvas.hxx>
+
+#include <osg/BlendFunc>
+#include <osg/Geometry>
+#include <osg/Texture2D>
+#include <osgGA/GUIEventHandler>
+
+/**
+ * Callback to enable/disable rendering of canvas displayed inside windows
+ */
+class CullCallback:
+ public osg::Drawable::CullCallback
+{
+ public:
+ CullCallback(Canvas::CameraCullCallback* camera_cull);
+
+ private:
+ Canvas::CameraCullCallback *_camera_cull;
+
+ virtual bool cull( osg::NodeVisitor* nv,
+ osg::Drawable* drawable,
+ osg::RenderInfo* renderInfo ) const;
+};
+
+//------------------------------------------------------------------------------
+CullCallback::CullCallback(Canvas::CameraCullCallback* camera_cull):
+ _camera_cull( camera_cull )
+{
+
+}
+
+//------------------------------------------------------------------------------
+bool CullCallback::cull( osg::NodeVisitor* nv,
+ osg::Drawable* drawable,
+ osg::RenderInfo* renderInfo ) const
+{
+ _camera_cull->enableRendering();
+ return false;
+}
+
+namespace canvas
+{
+ //----------------------------------------------------------------------------
+ Window::Window(SGPropertyNode* node):
+ PropertyBasedElement(node),
+ _dirty(true),
+ _geometry( new osg::Geometry ),
+ _vertices( new osg::Vec3Array(4) ),
+ _tex_coords( new osg::Vec2Array(4) ),
+ _x(node, "x"),
+ _y(node, "y"),
+ _width(node, "size[0]"),
+ _height(node, "size[1]")
+ {
+ _x = 50;
+ _y = 100;
+ _width = 400;
+ _height = 300;
+
+ _geometry->setVertexArray(_vertices);
+ _geometry->setTexCoordArray(0,_tex_coords);
+
+ osg::Vec4Array* colors = new osg::Vec4Array(1);
+ (*colors)[0].set(1.0f,1.0f,1.0,1.0f);
+ _geometry->setColorArray(colors);
+ _geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
+
+ _geometry->addPrimitiveSet(
+ new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)
+ );
+ _geometry->setDataVariance(osg::Object::DYNAMIC);
+
+ osg::StateSet* stateSet = _geometry->getOrCreateStateSet();
+ stateSet->setRenderBinDetails(1000, "RenderBin");
+
+ // speed optimization?
+ stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
+ stateSet->setAttribute(new osg::BlendFunc(
+ osg::BlendFunc::SRC_ALPHA,
+ osg::BlendFunc::ONE_MINUS_SRC_ALPHA)
+ );
+ stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
+ stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
+ stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
+ stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
+ stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
+ }
+
+ //----------------------------------------------------------------------------
+ Window::~Window()
+ {
+
+ }
+
+ //----------------------------------------------------------------------------
+ void Window::update(double delta_time_sec)
+ {
+ if( !_dirty )
+ return;
+ _dirty = false;
+
+ _region.set(_x, _y, _width, _height);
+
+ int z = 0; // TODO do we need to use z for depth ordering?
+
+ (*_vertices)[0].set(_region.l(), _region.t(), z);
+ (*_vertices)[1].set(_region.r(), _region.t(), z);
+ (*_vertices)[2].set(_region.r(), _region.b(), z);
+ (*_vertices)[3].set(_region.l(), _region.b(), z);
+
+ float l = 0, t = 1, b = 0, r = 1;
+ (*_tex_coords)[0].set(l,t);
+ (*_tex_coords)[1].set(r,t);
+ (*_tex_coords)[2].set(r,b);
+ (*_tex_coords)[3].set(l,b);
+
+ _geometry->dirtyDisplayList();
+ }
+
+ //----------------------------------------------------------------------------
+ void Window::valueChanged (SGPropertyNode * node)
+ {
+ if( node->getParent() != _node )
+ return;
+
+ const std::string& name = node->getNameString();
+ if( name == "x" || name == "y" || name == "size" )
+ _dirty = true;
+ }
+
+ //----------------------------------------------------------------------------
+ void Window::setCanvas(CanvasPtr canvas)
+ {
+ _canvas = canvas;
+ _geometry->getOrCreateStateSet()
+ ->setTextureAttribute(0, canvas ? canvas->getTexture() : 0);
+ _geometry->dirtyDisplayList();
+ _geometry->setCullCallback(
+ canvas ? new CullCallback(canvas->getCameraCullCallback()) : 0
+ );
+ }
+
+ //----------------------------------------------------------------------------
+ CanvasWeakPtr Window::getCanvas() const
+ {
+ return _canvas;
+ }
+
+ //----------------------------------------------------------------------------
+ bool Window::handleMouseEvent(const MouseEvent& event)
+ {
+ if( !_canvas.expired() )
+ return _canvas.lock()->handleMouseEvent(event);
+ else
+ return false;
+ }
+
+} // namespace canvas
--- /dev/null
+// Window for placing a Canvas onto it (for dialogs, menus, etc.)
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef CANVAS_WINDOW_HXX_
+#define CANVAS_WINDOW_HXX_
+
+#include "property_based_element.hxx"
+#include "rect.hxx"
+#include <Canvas/MouseEvent.hxx>
+
+#include <simgear/props/propertyObject.hxx>
+
+#include <osg/Geometry>
+
+namespace canvas
+{
+ class Window:
+ public PropertyBasedElement
+ {
+ public:
+ Window(SGPropertyNode* node);
+ virtual ~Window();
+
+ virtual void update(double delta_time_sec);
+ virtual void valueChanged (SGPropertyNode * node);
+
+ osg::Drawable* getDrawable() { return _geometry; }
+ const Rect<int>& getRegion() const { return _region; }
+
+ void setCanvas(CanvasPtr canvas);
+ CanvasWeakPtr getCanvas() const;
+
+ bool handleMouseEvent(const MouseEvent& event);
+
+ protected:
+
+ bool _dirty;
+
+ osg::ref_ptr<osg::Geometry> _geometry;
+ osg::ref_ptr<osg::Vec3Array> _vertices;
+ osg::ref_ptr<osg::Vec2Array> _tex_coords;
+
+ simgear::PropertyObject<int> _x, _y,
+ _width, _height;
+ Rect<int> _region;
+
+ CanvasWeakPtr _canvas;
+ };
+} // namespace canvas
+
+#endif /* CANVAS_WINDOW_HXX_ */
namespace JSBSim {
-static const char *IdSrc = "$Id: FGPropulsion.cpp,v 1.61 2012/04/14 18:10:44 bcoconni Exp $";
+static const char *IdSrc = "$Id: FGPropulsion.cpp,v 1.62 2012/07/19 03:50:19 jberndt Exp $";
static const char *IdHdr = ID_PROPULSION;
extern short debug_lvl;
const FGMatrix33& FGPropulsion::CalculateTankInertias(void)
{
- const FGMatrix33 Ts2b(-inchtoft, 0., 0., 0., inchtoft, 0., 0., 0., -inchtoft);
unsigned int size;
size = Tanks.size();
tankJ = FGMatrix33();
for (unsigned int i=0; i<size; i++) {
- FGColumnVector3 vTankBodyVec = Ts2b * (in.vXYZcg - Tanks[i]->GetXYZ());
+ FGColumnVector3 vTankStructVec = in.vXYZcg - Tanks[i]->GetXYZ();
tankJ += FDMExec->GetMassBalance()->GetPointmassInertia( lbtoslug * Tanks[i]->GetContents(),
- vTankBodyVec);
+ vTankStructVec);
tankJ(1,1) += Tanks[i]->GetIxx();
tankJ(2,2) += Tanks[i]->GetIyy();
tankJ(3,3) += Tanks[i]->GetIzz();
set(SOURCES
AirportList.cxx
+ CanvasWidget.cxx
MapWidget.cxx
WaypointList.cxx
dialog.cxx
set(HEADERS
AirportList.hxx
+ CanvasWidget.hxx
MapWidget.hxx
WaypointList.hxx
dialog.hxx
--- /dev/null
+/*
+ * CanvasWidget.cxx
+ *
+ * Created on: 03.07.2012
+ * Author: tom
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "CanvasWidget.hxx"
+
+#include <Canvas/canvas_mgr.hxx>
+#include <Main/fg_os.hxx> // fgGetKeyModifiers()
+#include <Scripting/NasalSys.hxx>
+
+//------------------------------------------------------------------------------
+CanvasWidget::CanvasWidget( int x, int y,
+ int width, int height,
+ SGPropertyNode* props,
+ const std::string& module ):
+ puObject(x, y, width, height),
+ _canvas_mgr( dynamic_cast<CanvasMgr*>(globals->get_subsystem("Canvas")) ),
+ _tex_id(0),
+ _no_tex_cnt(0)
+{
+ if( !_canvas_mgr )
+ {
+ SG_LOG(SG_GENERAL, SG_ALERT, "CanvasWidget: failed to get canvas manager!");
+ return;
+ }
+
+ // Get the first unused canvas slot
+ SGPropertyNode* canvas_root = fgGetNode("/canvas", true);
+ for(int index = 0;; ++index)
+ {
+ if( !canvas_root->getChild("texture", index) )
+ {
+ int view[2] = {
+ // Get canvas viewport size. If not specified use the widget dimensions
+ props->getIntValue("view[0]", width),
+ props->getIntValue("view[1]", height)
+ };
+ _canvas = canvas_root->getChild("texture", index, true);
+ _canvas->setIntValue("size[0]", view[0] * 2); // use higher resolution
+ _canvas->setIntValue("size[1]", view[1] * 2); // for antialias
+ _canvas->setIntValue("view[0]", view[0]);
+ _canvas->setIntValue("view[1]", view[1]);
+ _canvas->setBoolValue("render-always", true);
+ _canvas->setStringValue( "name",
+ props->getStringValue("name", "gui-anonymous") );
+ SGPropertyNode* input = _canvas->getChild("input", 0, true);
+ _mouse_x = input->getChild("mouse-x", 0, true);
+ _mouse_y = input->getChild("mouse-y", 0, true);
+ _mouse_down = input->getChild("mouse-down", 0, true);
+ _mouse_drag = input->getChild("mouse-drag", 0, true);
+
+ SGPropertyNode *nasal = props->getNode("nasal");
+ if( !nasal )
+ break;
+
+ FGNasalSys *nas =
+ dynamic_cast<FGNasalSys*>(globals->get_subsystem("nasal"));
+ if( !nas )
+ SG_LOG( SG_GENERAL,
+ SG_ALERT,
+ "CanvasWidget: Failed to get nasal subsystem!" );
+
+ const std::string file = std::string("__canvas:")
+ + _canvas->getStringValue("name");
+
+ SGPropertyNode *load = nasal->getNode("load");
+ if( load )
+ {
+ const char *s = load->getStringValue();
+ nas->handleCommand(module.c_str(), file.c_str(), s, _canvas);
+ }
+ break;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+CanvasWidget::~CanvasWidget()
+{
+ if( _canvas )
+ _canvas->getParent()
+ ->removeChild(_canvas->getName(), _canvas->getIndex(), false);
+}
+
+//------------------------------------------------------------------------------
+void CanvasWidget::doHit(int button, int updown, int x, int y)
+{
+ puObject::doHit(button, updown, x, y);
+
+ // CTRL allows resizing and SHIFT allows moving the window
+ if( fgGetKeyModifiers() & (KEYMOD_CTRL | KEYMOD_SHIFT) )
+ return;
+
+ _mouse_x->setIntValue(x - abox.min[0]);
+ _mouse_y->setIntValue(abox.max[1] - y);
+
+ if( updown == PU_DRAG )
+ _mouse_drag->setIntValue(button);
+ else if( updown == PU_DOWN )
+ _mouse_down->setIntValue(button);
+
+ if( button != active_mouse_button )
+ return;
+
+ if (updown == PU_UP)
+ puDeactivateWidget();
+ else if (updown == PU_DOWN)
+ puSetActiveWidget(this, x, y);
+}
+
+//------------------------------------------------------------------------------
+int CanvasWidget::checkKey(int key, int updown)
+{
+ return puObject::checkKey(key, updown);
+}
+
+//------------------------------------------------------------------------------
+void CanvasWidget::setSize(int w, int h)
+{
+ puObject::setSize(w, h);
+
+ _canvas->setIntValue("view[0]", w);
+ _canvas->setIntValue("view[1]", h);
+}
+
+//------------------------------------------------------------------------------
+void CanvasWidget::draw(int dx, int dy)
+{
+ if( !_tex_id )
+ {
+ _tex_id = _canvas_mgr->getCanvasTexId(_canvas->getIndex());
+
+ // Normally we should be able to get the texture after one frame. I don't
+ // know if there are circumstances where it can take longer, so we don't
+ // log a warning message until we have tried a few times.
+ if( !_tex_id )
+ {
+ if( ++_no_tex_cnt == 5 )
+ SG_LOG(SG_GENERAL, SG_WARN, "CanvasWidget: failed to get texture!");
+ return;
+ }
+ else
+ {
+ if( _no_tex_cnt >= 5 )
+ SG_LOG
+ (
+ SG_GENERAL,
+ SG_INFO,
+ "CanvasWidget: got texture after " << _no_tex_cnt << " tries."
+ );
+ _no_tex_cnt = 0;
+ }
+ }
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, _tex_id);
+ glBegin( GL_QUADS );
+ glColor3f(1,1,1);
+ glTexCoord2f(0,0); glVertex2f(dx + abox.min[0], dy + abox.min[1]);
+ glTexCoord2f(1,0); glVertex2f(dx + abox.max[0], dy + abox.min[1]);
+ glTexCoord2f(1,1); glVertex2f(dx + abox.max[0], dy + abox.max[1]);
+ glTexCoord2f(0,1); glVertex2f(dx + abox.min[0], dy + abox.max[1]);
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+}
--- /dev/null
+/*
+ * CanvasWidget.hxx
+ *
+ * Created on: 03.07.2012
+ * Author: tom
+ */
+
+#ifndef CANVASWIDGET_HXX_
+#define CANVASWIDGET_HXX_
+
+#include <Main/fg_props.hxx>
+#include <plib/pu.h>
+
+class CanvasMgr;
+
+class CanvasWidget:
+ public puObject
+{
+ public:
+ CanvasWidget( int x, int y,
+ int width, int height,
+ SGPropertyNode* props,
+ const std::string& module );
+ virtual ~CanvasWidget();
+
+ virtual void doHit (int button, int updown, int x, int y);
+ virtual int checkKey(int key , int updown);
+
+ virtual void setSize ( int w, int h );
+ virtual void draw(int dx, int dy);
+
+ private:
+
+ CanvasMgr *_canvas_mgr; // TODO maybe we should store this in some central
+ // location or make it static...
+
+ GLuint _tex_id; //<! OpenGL texture id if canvas
+ size_t _no_tex_cnt;//<! Count since how many frames we were not
+ // able to get the texture (for debugging)
+ SGPropertyNode_ptr _canvas; //<! Canvas root property node
+ SGPropertyNode *_mouse_x,
+ *_mouse_y,
+ *_mouse_down,
+ *_mouse_drag;
+};
+
+#endif /* CANVASWIDGET_HXX_ */
{ "HELVETICA_12", &FONT_HELVETICA_12 },
{ "HELVETICA_14", &FONT_HELVETICA_14 },
{ "HELVETICA_18", &PUFONT_HELVETICA_18 },
- { "SANS_12B", &FONT_SANS_12B }
+ { "SANS_12B", &FONT_SANS_12B },
+ { 0 }
};
-const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])];
+const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])-1];
}
FGFontCache::FGFontCache() :
#include "property_list.hxx"
#include "layout.hxx"
#include "WaypointList.hxx"
+#include "CanvasWidget.hxx"
#include "MapWidget.hxx"
#include "FGFontCache.hxx"
#include "FGColor.hxx"
MapWidget* mapWidget = new MapWidget(x, y, x + width, y + height);
setupObject(mapWidget, props);
return mapWidget;
+ } else if (type == "canvas") {
+ CanvasWidget* canvasWidget = new CanvasWidget( x, y,
+ x + width, y + height,
+ props,
+ _module );
+ setupObject(canvasWidget, props);
+ return canvasWidget;
} else if (type == "combo") {
fgComboBox *obj = new fgComboBox(x, y, x + width, y + height, props,
props->getBoolValue("editable", false));
_active_dialog(0)
{
#if defined(SG_MAC)
- _menubar.reset(new FGCocoaMenuBar);
-#else
- _menubar.reset(new FGPUIMenuBar);
+ if (fgGetBool("/sim/menubar/native", true)) {
+ _menubar.reset(new FGCocoaMenuBar);
+ return;
+ }
#endif
+ _menubar.reset(new FGPUIMenuBar);
}
NewGUI::~NewGUI ()
{
string branch;
branch = "/instrumentation/" + _name;
-
SGPropertyNode *node = fgGetNode(branch.c_str(), _num, true );
- _longitude_node = fgGetNode("/position/longitude-deg", true);
- _latitude_node = fgGetNode("/position/latitude-deg", true);
- _altitude_node = fgGetNode("/position/altitude-ft", true);
- _heading_node = fgGetNode("/orientation/heading-deg", true);
- _serviceable_node = node->getChild("serviceable", 0, true);
- _error_node = node->getChild("error-deg", 0, true);
- _electrical_node = fgGetNode("/systems/electrical/outputs/adf", true);
- branch = branch + "/frequencies";
- SGPropertyNode *fnode = node->getChild("frequencies", 0, true);
- _frequency_node = fnode->getChild("selected-khz", 0, true);
- _mode_node = node->getChild("mode", 0, true);
- _volume_node = node->getChild("volume-norm", 0, true);
- _in_range_node = node->getChild("in-range", 0, true);
- _bearing_node = node->getChild("indicated-bearing-deg", 0, true);
- _ident_node = node->getChild("ident", 0, true);
+
+ // instrument properties
+ _error_node = node->getChild("error-deg", 0, true);
+ _mode_node = node->getChild("mode", 0, true);
+ _volume_node = node->getChild("volume-norm", 0, true);
+ _in_range_node = node->getChild("in-range", 0, true);
+ _bearing_node = node->getChild("indicated-bearing-deg", 0, true);
+ _ident_node = node->getChild("ident", 0, true);
_ident_audible_node = node->getChild("ident-audible", 0, true);
- _power_btn_node = node->getChild("power-btn", 0, true);
+ _serviceable_node = node->getChild("serviceable", 0, true);
+ _power_btn_node = node->getChild("power-btn", 0, true);
+ _operable_node = node->getChild("operable", 0, true);
+ // frequency properties
+ SGPropertyNode *fnode = node->getChild("frequencies", 0, true);
+ _frequency_node = fnode->getChild("selected-khz", 0, true);
+
+ // foreign simulator properties
+ _electrical_node = fgGetNode("/systems/electrical/outputs/adf", true);
+ _longitude_node = fgGetNode("/position/longitude-deg", true);
+ _latitude_node = fgGetNode("/position/latitude-deg", true);
+ _altitude_node = fgGetNode("/position/altitude-ft", true);
+ _heading_node = fgGetNode("/orientation/heading-deg", true);
+
+ // backward compatibility check
if (_power_btn_node->getType() == simgear::props::NONE)
_power_btn_node->setBoolValue(true); // front end didn't implement a power button
+ // sound support (audible ident code)
SGSoundMgr *smgr = globals->get_soundmgr();
_sgr = smgr->find("avionics", true);
_sgr->tie_to_listener();
|| !_serviceable_node->getBoolValue()
|| !_power_btn_node->getBoolValue() ) {
_in_range_node->setBoolValue(false);
+ _operable_node->setBoolValue(false);
_ident_node->setStringValue("");
return;
}
+ _operable_node->setBoolValue(true);
+
string mode = _mode_node->getStringValue();
if (mode == "ant" || mode == "test") set_bearing(delta_time_sec, 90);
if (mode != "bfo" && mode != "adf") {
SGPropertyNode_ptr _ident_audible_node;
SGPropertyNode_ptr _volume_node;
SGPropertyNode_ptr _power_btn_node;
+ SGPropertyNode_ptr _operable_node;
double _time_before_search_sec;
set_subsystem( id, new VerticalSpeedIndicator( node ) );
} else if ( name == "radar" ) {
- set_subsystem( id, new wxRadarBg ( node ), 1);
+ set_subsystem( id, new wxRadarBg ( node ) );
} else if ( name == "inst-vertical-speed-indicator" ) {
set_subsystem( id, new InstVerticalSpeedIndicator( node ) );
set_subsystem( id, new MasterReferenceGyro( node ) );
} else if ( name == "groundradar" ) {
- set_subsystem( id, new GroundRadar( node ), 1 );
+ set_subsystem( id, new GroundRadar( node ) );
} else if ( name == "air-ground-radar" ) {
- set_subsystem( id, new agRadar( node ),1);
+ set_subsystem( id, new agRadar( node ) );
} else if ( name == "radar-altimeter" ) {
- set_subsystem( id, new radAlt( node ),1);
+ set_subsystem( id, new radAlt( node ) );
} else if ( name == "tcas" ) {
set_subsystem( id, new TCAS( node ), 0.2);
{
SGPropertyNode* node = _radio_node.get();
bus_power_node =
- fgGetNode(("/systems/electrical/outputs/" + _name).c_str(), true);
+ fgGetNode(("/systems/electrical/outputs/" + _name).c_str(), true);
// inputs
is_valid_node = node->getChild("data-is-valid", 0, true);
texture->setFilter(
osg::Texture2D::MIN_FILTER,
- _use_mipmapping ? osg::Texture2D::LINEAR_MIPMAP_NEAREST
+ _use_mipmapping ? osg::Texture2D::LINEAR_MIPMAP_LINEAR
: osg::Texture2D::LINEAR
);
camera->attach(
* Get a list of groups which have been inserted into the scene graph to
* replace the given texture
*/
- Placements& getPlacements()
+ canvas::Placements& getPlacements()
{
return _placements;
}
if( _cull_callback )
group->setCullCallback(_cull_callback);
- _placements.push_back(group);
+ _placements.push_back(
+ canvas::PlacementPtr(new ObjectPlacement(group))
+ );
osg::StateSet* stateSet = group->getOrCreateStateSet();
stateSet->setTextureAttribute( unit, _new_texture,
}
}
+ protected:
+ class ObjectPlacement:
+ public canvas::Placement
+ {
+ public:
+ ObjectPlacement(osg::ref_ptr<osg::Group> group):
+ _group(group)
+ {}
+
+ /**
+ * Remove placement from the scene
+ */
+ virtual ~ObjectPlacement()
+ {
+ assert( _group->getNumChildren() == 1 );
+ osg::Node *child = _group->getChild(0);
- protected:
+ if( _group->getNumParents() )
+ {
+ osg::Group *parent = _group->getParent(0);
+ parent->addChild(child);
+ parent->removeChild(_group);
+ }
+
+ _group->removeChild(child);
+ }
+
+ private:
+ osg::ref_ptr<osg::Group> _group;
+ };
std::string _tex_name, ///<! Name of texture to be replaced
_node_name, ///<! Only replace if node name matches
osg::Texture2D *_new_texture;
osg::NodeCallback *_cull_callback;
- Placements _placements;
+ canvas::Placements _placements;
};
//------------------------------------------------------------------------------
- Placements FGODGauge::set_texture(const char* name, osg::Texture2D* new_texture)
+canvas::Placements FGODGauge::set_texture( const char* name,
+ osg::Texture2D* new_texture )
{
osg::Group* root = globals->get_scenery()->get_aircraft_branch();
ReplaceStaticTextureVisitor visitor(name, new_texture);
}
//------------------------------------------------------------------------------
-Placements FGODGauge::set_texture( const SGPropertyNode* placement,
- osg::Texture2D* new_texture,
- osg::NodeCallback* cull_callback )
+canvas::Placements FGODGauge::set_texture( const SGPropertyNode* placement,
+ osg::Texture2D* new_texture,
+ osg::NodeCallback* cull_callback )
{
osg::Group* root = globals->get_scenery()->get_aircraft_branch();
ReplaceStaticTextureVisitor visitor(placement, new_texture, cull_callback);
#ifndef _OD_GAUGE_HXX
#define _OD_GAUGE_HXX
+#include <Canvas/canvas_fwd.hpp>
+#include <Canvas/placement.hxx>
+
#include <osg/NodeCallback>
#include <osg/Group>
}
class SGPropertyNode;
-typedef std::vector<osg::ref_ptr<osg::Group> > Placements;
/**
* Owner Drawn Gauge helper class.
*/
class FGODGauge
{
-public:
+ public:
FGODGauge();
virtual ~FGODGauge();
* @param new_texture dynamic texture to replace the old one
* @return A list of groups which override the given texture
*/
- Placements set_texture(const char * name, osg::Texture2D* new_texture);
+ static
+ canvas::Placements set_texture( const char * name,
+ osg::Texture2D* new_texture );
/**
* Replace an opengl texture name inside the aircraft scene graph.
* object
* @return A list of groups which override the given texture
*/
- Placements set_texture( const SGPropertyNode* placement,
- osg::Texture2D* new_texture,
- osg::NodeCallback* cull_callback = 0 );
+ static
+ canvas::Placements set_texture( const SGPropertyNode* placement,
+ osg::Texture2D* new_texture,
+ osg::NodeCallback* cull_callback = 0 );
/**
* Get the OSG camera for drawing this gauge.
*/
- osg::Camera* getCamera() { return camera.get(); }
+ osg::Camera* getCamera() const { return camera.get(); }
- osg::Texture2D* getTexture() { return texture.get(); }
+ osg::Texture2D* getTexture() const { return texture.get(); }
//void setTexture(osg::Texture2D* t) { texture = t; }
// Real initialization function. Bad name.
camera->addChild(_textGeode.get());
updateFont();
+ _time = 0.0;
}
if (_time < _interval)
return;
- _time = 0.0;
+ _time -= _interval;
string mode = _Instrument->getStringValue("display-mode", "arc");
if (mode == "map") {
return true;
}
+/**
+ * Reload the materials definition
+ */
+ static bool
+ do_materials_reload (const SGPropertyNode * arg)
+ {
+ SG_LOG(SG_INPUT, SG_INFO, "Reloading Materials");
+ SGMaterialLib* new_matlib = new SGMaterialLib;
+ SGPath mpath( globals->get_fg_root() );
+ mpath.append( fgGetString("/sim/rendering/materials-file") );
+ bool loaded = new_matlib->load(globals->get_fg_root(),
+ mpath.str(),
+ globals->get_props());
+
+ if ( ! loaded ) {
+ SG_LOG( SG_GENERAL, SG_ALERT,
+ "Error loading materials file " << mpath.str() );
+ return false;
+ }
+
+ globals->set_matlib(new_matlib);
+ return true;
+ }
+
#if 0
These do_set_(some-environment-parameters) are deprecated and no longer
{ "dump-terrainbranch", do_dump_terrain_branch },
{ "print-visible-scene", do_print_visible_scene_info },
{ "reload-shaders", do_reload_shaders },
+ { "reload-materials", do_materials_reload },
{ 0, 0 } // zero-terminated
};
#include <Cockpit/panel_io.hxx>
#include <Canvas/canvas_mgr.hxx>
+#include <Canvas/gui_mgr.hxx>
#include <GUI/new_gui.hxx>
#include <Input/input.hxx>
#include <Instrumentation/instrument_mgr.hxx>
////////////////////////////////////////////////////////////////////
// Initialize the canvas 2d drawing subsystem.
////////////////////////////////////////////////////////////////////
- globals->add_subsystem("Canvas2D", new CanvasMgr, SGSubsystemMgr::DISPLAY);
+ globals->add_subsystem("Canvas", new CanvasMgr, SGSubsystemMgr::DISPLAY);
+ globals->add_subsystem("CanvasGUI", new GUIMgr, SGSubsystemMgr::DISPLAY);
////////////////////////////////////////////////////////////////////
// Initialise the ATIS Manager
#include <simgear/io/HTTPClient.hxx>
#include <simgear/io/HTTPRequest.hxx>
+#include <simgear/io/raw_socket.hxx>
#include <simgear/timing/timestamp.hxx>
using namespace std;
string proxy_host, proxy_port;
getproxy(proxy_host, proxy_port);
+ Socket::initSockets();
+
HTTP::Client http;
http.setProxy(proxy_host, atoi(proxy_port.c_str()));
<< t.getFormattedMessage() << t.getOrigin());
return;
}
-
+
Instance * instance = new Instance;
SGModelPlacement *model = new SGModelPlacement;
instance->model = model;
{
SGModelPlacement* model = instance->model;
double lon, lat, elev, roll, pitch, heading;
+ lon = lat = elev = roll = pitch = heading = 0.0;
try {
// Optionally set position from properties
SGSharedPtr<PropertyReferenceSet> _propertyReferenceSet;
};
-class MPAttributeCallback : public sg::HLAObjectInstance::AttributeCallback {
+class MPAttributeData {
public:
- MPAttributeCallback() :
+ MPAttributeData() :
_propertyReferenceSet(new PropertyReferenceSet),
_mpProperties(new sg::HLAVariantArrayDataElement)
{
_mpProperties->setAlternativeDataElementFactory(new MPPropertyVariantRecordDataElementFactory(_propertyReferenceSet.get()));
}
- virtual ~MPAttributeCallback()
- { }
void setLocation(sg::HLAAbstractLocation* location)
{ _location = location; }
{ return _mpProperties.get(); }
SGSharedPtr<PropertyReferenceSet> _propertyReferenceSet;
-
-protected:
SGSharedPtr<sg::HLAAbstractLocation> _location;
SGSharedPtr<AbstractSimTime> _simTime;
SGSharedPtr<AbstractModel> _model;
SGSharedPtr<sg::HLAVariantArrayDataElement> _mpProperties;
};
-class MPOutAttributeCallback : public MPAttributeCallback {
+class MPUpdateCallback : public sg::HLAObjectInstance::UpdateCallback {
public:
- virtual void updateAttributeValues(sg::HLAObjectInstance&, const sg::RTIData&)
+ virtual void updateAttributeValues(sg::HLAObjectInstance& objectInstance, const sg::RTIData& tag)
+ {
+ updateAttributeValues();
+ objectInstance.encodeAttributeValues();
+ objectInstance.sendAttributeValues(tag);
+ }
+
+ virtual void updateAttributeValues(sg::HLAObjectInstance& objectInstance, const SGTimeStamp& timeStamp, const sg::RTIData& tag)
+ {
+ updateAttributeValues();
+ objectInstance.encodeAttributeValues();
+ objectInstance.sendAttributeValues(timeStamp, tag);
+ }
+
+ void updateAttributeValues()
{
- _simTime->setTimeStamp(globals->get_sim_time_sec());
+ _attributeData._simTime->setTimeStamp(globals->get_sim_time_sec());
- SGGeod position = ifce.getPosition();
+ SGGeod position = _ifce.getPosition();
// The quaternion rotating from the earth centered frame to the
// horizontal local frame
SGQuatd qEc2Hl = SGQuatd::fromLonLat(position);
- SGQuatd hlOr = SGQuatd::fromYawPitchRoll(ifce.get_Psi(), ifce.get_Theta(), ifce.get_Phi());
- _location->setCartPosition(SGVec3d::fromGeod(position));
- _location->setCartOrientation(qEc2Hl*hlOr);
+ SGQuatd hlOr = SGQuatd::fromYawPitchRoll(_ifce.get_Psi(), _ifce.get_Theta(), _ifce.get_Phi());
+ _attributeData._location->setCartPosition(SGVec3d::fromGeod(position));
+ _attributeData._location->setCartOrientation(qEc2Hl*hlOr);
// The angular velocitied in the body frame
- double p = ifce.get_P_body();
- double q = ifce.get_Q_body();
- double r = ifce.get_R_body();
- _location->setAngularBodyVelocity(SGVec3d(p, q, r));
+ double p = _ifce.get_P_body();
+ double q = _ifce.get_Q_body();
+ double r = _ifce.get_R_body();
+ _attributeData._location->setAngularBodyVelocity(SGVec3d(p, q, r));
// The body uvw velocities in the interface are wrt the wind instead
// of wrt the ec frame
- double n = ifce.get_V_north();
- double e = ifce.get_V_east();
- double d = ifce.get_V_down();
- _location->setLinearBodyVelocity(hlOr.transform(SGVec3d(n, e, d)));
-
- if (_mpProperties.valid() && _mpProperties->getNumElements() == 0) {
- if (_propertyReferenceSet.valid() && _propertyReferenceSet->getRootNode()) {
- const sg::HLADataType* elementDataType = _mpProperties->getElementDataType();
+ double n = _ifce.get_V_north();
+ double e = _ifce.get_V_east();
+ double d = _ifce.get_V_down();
+ _attributeData._location->setLinearBodyVelocity(hlOr.transform(SGVec3d(n, e, d)));
+
+ if (_attributeData._mpProperties.valid() && _attributeData._mpProperties->getNumElements() == 0) {
+ if (_attributeData._propertyReferenceSet.valid() && _attributeData._propertyReferenceSet->getRootNode()) {
+ const sg::HLADataType* elementDataType = _attributeData._mpProperties->getElementDataType();
const sg::HLAVariantRecordDataType* variantRecordDataType = elementDataType->toVariantRecordDataType();
for (unsigned i = 0, count = 0; i < variantRecordDataType->getNumAlternatives(); ++i) {
std::string name = variantRecordDataType->getAlternativeSemantics(i);
- SGPropertyNode* node = _propertyReferenceSet->getRootNode()->getNode(name);
+ SGPropertyNode* node = _attributeData._propertyReferenceSet->getRootNode()->getNode(name);
if (!node)
continue;
- _mpProperties->getOrCreateElement(count++)->setAlternativeIndex(i);
+ _attributeData._mpProperties->getOrCreateElement(count++)->setAlternativeIndex(i);
}
}
}
}
-private:
- FlightProperties ifce;
+ MPAttributeData _attributeData;
+ FlightProperties _ifce;
};
-class MPInAttributeCallback : public MPAttributeCallback {
+class MPReflectCallback : public sg::HLAObjectInstance::ReflectCallback {
public:
virtual void reflectAttributeValues(sg::HLAObjectInstance& objectInstance,
- const sg::RTIIndexDataPairList&, const sg::RTIData&)
+ const sg::HLAIndexList& indexList, const sg::RTIData& tag)
+ {
+ objectInstance.reflectAttributeValues(indexList, tag);
+ reflectAttributeValues();
+ }
+ virtual void reflectAttributeValues(sg::HLAObjectInstance& objectInstance, const sg::HLAIndexList& indexList,
+ const SGTimeStamp& timeStamp, const sg::RTIData& tag)
+ {
+ objectInstance.reflectAttributeValues(indexList, timeStamp, tag);
+ reflectAttributeValues();
+ }
+
+ void reflectAttributeValues()
{
// Puh, damn ordering problems with properties startup and so on
if (_aiMultiplayer.valid()) {
FGExternalMotionData motionInfo;
- motionInfo.time = _simTime->getTimeStamp();
+ motionInfo.time = _attributeData._simTime->getTimeStamp();
motionInfo.lag = 0;
- motionInfo.position = _location->getCartPosition();
- motionInfo.orientation = toQuatf(_location->getCartOrientation());
- motionInfo.linearVel = toVec3f(_location->getLinearBodyVelocity());
- motionInfo.angularVel = toVec3f(_location->getAngularBodyVelocity());
+ motionInfo.position = _attributeData._location->getCartPosition();
+ motionInfo.orientation = toQuatf(_attributeData._location->getCartOrientation());
+ motionInfo.linearVel = toVec3f(_attributeData._location->getLinearBodyVelocity());
+ motionInfo.angularVel = toVec3f(_attributeData._location->getAngularBodyVelocity());
motionInfo.linearAccel = SGVec3f::zeros();
motionInfo.angularAccel = SGVec3f::zeros();
_aiMultiplayer->addMotionInfo(motionInfo, SGTimeStamp::now().getSeconds());
} else {
- std::string modelPath = _model->getModelPath();
+ std::string modelPath = _attributeData._model->getModelPath();
if (modelPath.empty())
return;
FGAIManager *aiMgr;
_aiMultiplayer->setPath(modelPath.c_str());
aiMgr->attach(_aiMultiplayer.get());
- _propertyReferenceSet->setRootNode(_aiMultiplayer->getPropertyRoot());
+ _attributeData._propertyReferenceSet->setRootNode(_aiMultiplayer->getPropertyRoot());
}
}
_aiMultiplayer = 0;
}
-private:
+ MPAttributeData _attributeData;
SGSharedPtr<FGAIMultiplayer> _aiMultiplayer;
};
virtual void discoverInstance(const sg::HLAObjectClass& objectClass, sg::HLAObjectInstance& objectInstance, const sg::RTIData& tag)
{
- MPInAttributeCallback* attributeCallback = new MPInAttributeCallback;
- objectInstance.setAttributeCallback(attributeCallback);
- attachDataElements(objectInstance, *attributeCallback, false);
+ MPReflectCallback* reflectCallback = new MPReflectCallback;
+ objectInstance.setReflectCallback(reflectCallback);
+ attachDataElements(objectInstance, reflectCallback->_attributeData, false);
}
virtual void removeInstance(const sg::HLAObjectClass& objectClass, sg::HLAObjectInstance& objectInstance, const sg::RTIData& tag)
{
- MPInAttributeCallback* attributeCallback;
- attributeCallback = dynamic_cast<MPInAttributeCallback*>(objectInstance.getAttributeCallback().get());
- if (!attributeCallback) {
+ MPReflectCallback* reflectCallback;
+ reflectCallback = dynamic_cast<MPReflectCallback*>(objectInstance.getReflectCallback().get());
+ if (!reflectCallback) {
SG_LOG(SG_IO, SG_WARN, "HLA: expected to have a different attribute callback in remove instance.");
return;
}
- attributeCallback->setDie();
+ reflectCallback->setDie();
}
virtual void registerInstance(const sg::HLAObjectClass& objectClass, sg::HLAObjectInstance& objectInstance)
{
- MPOutAttributeCallback* attributeCallback = new MPOutAttributeCallback;
- objectInstance.setAttributeCallback(attributeCallback);
- attachDataElements(objectInstance, *attributeCallback, true);
- attributeCallback->_propertyReferenceSet->setRootNode(fgGetNode("/", true));
+ MPUpdateCallback* updateCallback = new MPUpdateCallback;
+ objectInstance.setUpdateCallback(updateCallback);
+ attachDataElements(objectInstance, updateCallback->_attributeData, true);
+ updateCallback->_attributeData._propertyReferenceSet->setRootNode(fgGetNode("/", true));
}
virtual void deleteInstance(const sg::HLAObjectClass& objectClass, sg::HLAObjectInstance& objectInstance)
}
private:
- void attachDataElements(sg::HLAObjectInstance& objectInstance, MPAttributeCallback& attributeCallback, bool outgoing)
+ void attachDataElements(sg::HLAObjectInstance& objectInstance, MPAttributeData& attributeData, bool outgoing)
{
sg::HLAAttributePathElementMap attributePathElementMap;
if (_locationFactory.valid())
- attributeCallback.setLocation(_locationFactory->createLocation(attributePathElementMap));
+ attributeData.setLocation(_locationFactory->createLocation(attributePathElementMap));
if (_modelFactory.valid())
- attributeCallback.setModel(_modelFactory->createModel(attributePathElementMap, outgoing));
+ attributeData.setModel(_modelFactory->createModel(attributePathElementMap, outgoing));
if (_simTimeFactory.valid())
- attributeCallback.setSimTime(_simTimeFactory->createSimTime(attributePathElementMap));
+ attributeData.setSimTime(_simTimeFactory->createSimTime(attributePathElementMap));
- attributePathElementMap[_mpPropertiesIndexPathPair.first][_mpPropertiesIndexPathPair.second] = attributeCallback.getMPProperties();
+ attributePathElementMap[_mpPropertiesIndexPathPair.first][_mpPropertiesIndexPathPair.second] = attributeData.getMPProperties();
if (outgoing)
- attachPropertyDataElements(*attributeCallback._propertyReferenceSet,
+ attachPropertyDataElements(*attributeData._propertyReferenceSet,
attributePathElementMap, _outputProperties);
else
- attachPropertyDataElements(*attributeCallback._propertyReferenceSet,
+ attachPropertyDataElements(*attributeData._propertyReferenceSet,
attributePathElementMap, _inputProperties);
objectInstance.setAttributes(attributePathElementMap);
return;
fgSetBool("/sim/sceneryloaded",false);
fgSetDouble("/sim/startup/splash-alpha", 1.0);
+
+ // Reload the materials definitions
+ _options->setMaterialLib(globals->get_matlib());
// remove all old scenery nodes from scenegraph and clear cache
osg::Group* group = globals->get_scenery()->get_terrain_branch();
NasalSys.cxx
nasal-props.cxx
NasalPositioned.cxx
+ NasalCanvas.cxx
)
set(HEADERS
NasalSys.hxx
NasalPositioned.hxx
+ NasalCanvas.hxx
)
--- /dev/null
+// NasalCanvas.cxx -- expose Canvas classes to Nasal
+//
+// Written by James Turner, started 2012.
+//
+// Copyright (C) 2012 James Turner
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include "NasalCanvas.hxx"
+
+#include <boost/foreach.hpp>
+#include <boost/algorithm/string/case_conv.hpp>
+
+#include <osgGA/GUIEventAdapter>
+
+#include <simgear/sg_inlines.h>
+
+#include <Canvas/canvas.hxx>
+#include <Canvas/elements/element.hxx>
+
+static naRef canvasPrototype;
+static naRef elementPrototype;
+static naRef eventPrototype;
+
+static void canvasGhostDestroy(void* g);
+static void elementGhostDestroy(void* g);
+static void eventGhostDestroy(void* g);
+
+static const char* canvasGhostGetMember(naContext c, void* g, naRef field, naRef* out);
+naGhostType CanvasGhostType = { canvasGhostDestroy, "canvas", canvasGhostGetMember, 0 };
+
+static const char* elementGhostGetMember(naContext c, void* g, naRef field, naRef* out);
+static void elementGhostSetMember(naContext c, void* g, naRef field, naRef value);
+naGhostType ElementGhostType = { elementGhostDestroy, "canvas.element",
+ elementGhostGetMember, elementGhostSetMember };
+
+static const char* eventGhostGetMember(naContext c, void* g, naRef field, naRef* out);
+naGhostType EventGhostType = { eventGhostDestroy, "ga-event", eventGhostGetMember, 0 };
+
+static void hashset(naContext c, naRef hash, const char* key, naRef val)
+{
+ naRef s = naNewString(c);
+ naStr_fromdata(s, (char*)key, strlen(key));
+ naHash_set(hash, s, val);
+}
+
+static naRef stringToNasal(naContext c, const std::string& s)
+{
+ return naStr_fromdata(naNewString(c),
+ const_cast<char *>(s.c_str()),
+ s.length());
+}
+
+static naRef eventTypeToNasal(naContext c, osgGA::GUIEventAdapter::EventType ty)
+{
+ switch (ty) {
+ case osgGA::GUIEventAdapter::PUSH: return stringToNasal(c, "push");
+ case osgGA::GUIEventAdapter::RELEASE: return stringToNasal(c, "release");
+ case osgGA::GUIEventAdapter::DOUBLECLICK: return stringToNasal(c, "double-click");
+ case osgGA::GUIEventAdapter::DRAG: return stringToNasal(c, "drag");
+ case osgGA::GUIEventAdapter::MOVE: return stringToNasal(c, "move");
+ case osgGA::GUIEventAdapter::SCROLL: return stringToNasal(c, "scroll");
+ case osgGA::GUIEventAdapter::KEYUP: return stringToNasal(c, "key-up");
+ case osgGA::GUIEventAdapter::KEYDOWN: return stringToNasal(c, "key-down");
+
+ default:
+ ; // fall through
+ }
+
+ return naNil();
+}
+
+static canvas::Element* elementGhost(naRef r)
+{
+ if (naGhost_type(r) == &ElementGhostType)
+ return (canvas::Element*) naGhost_ptr(r);
+ return 0;
+}
+
+static Canvas* canvasGhost(naRef r)
+{
+ if (naGhost_type(r) == &CanvasGhostType)
+ return (Canvas*) naGhost_ptr(r);
+ return 0;
+}
+
+static void elementGhostDestroy(void* g)
+{
+}
+
+static void canvasGhostDestroy(void* g)
+{
+}
+
+static void eventGhostDestroy(void* g)
+{
+ osgGA::GUIEventAdapter* gea = static_cast<osgGA::GUIEventAdapter*>(g);
+ gea->unref();
+}
+
+static const char* eventGhostGetMember(naContext c, void* g, naRef field, naRef* out)
+{
+ const char* fieldName = naStr_data(field);
+ osgGA::GUIEventAdapter* gea = (osgGA::GUIEventAdapter*) g;
+
+ if (!strcmp(fieldName, "parents")) {
+ *out = naNewVector(c);
+ naVec_append(*out, eventPrototype);
+ } else if (!strcmp(fieldName, "type")) *out = eventTypeToNasal(c, gea->getEventType());
+ else if (!strcmp(fieldName, "windowX")) *out = naNum(gea->getWindowX());
+ else if (!strcmp(fieldName, "windowY")) *out = naNum(gea->getWindowY());
+ else if (!strcmp(fieldName, "time")) *out = naNum(gea->getTime());
+ else if (!strcmp(fieldName, "button")) *out = naNum(gea->getButton());
+ else {
+ return 0;
+ }
+
+ return "";
+}
+
+static const char* canvasGhostGetMember(naContext c, void* g, naRef field, naRef* out)
+{
+ const char* fieldName = naStr_data(field);
+ Canvas* cvs = (Canvas*) g;
+
+ if (!strcmp(fieldName, "parents")) {
+ *out = naNewVector(c);
+ naVec_append(*out, canvasPrototype);
+ } else if (!strcmp(fieldName, "sizeX")) *out = naNum(cvs->getSizeX());
+ else if (!strcmp(fieldName, "sizeY")) *out = naNum(cvs->getSizeY());
+ else {
+ return 0;
+ }
+
+ return "";
+}
+
+static const char* elementGhostGetMember(naContext c, void* g, naRef field, naRef* out)
+{
+ const char* fieldName = naStr_data(field);
+ canvas::Element* e = (canvas::Element*) g;
+
+ if (!strcmp(fieldName, "parents")) {
+ *out = naNewVector(c);
+ naVec_append(*out, elementPrototype);
+ } else {
+ return 0;
+ }
+
+ return "";
+}
+
+static void elementGhostSetMember(naContext c, void* g, naRef field, naRef value)
+{
+ const char* fieldName = naStr_data(field);
+ canvas::Element* e = (canvas::Element*) g;
+}
+
+
+static naRef f_canvas_getElement(naContext c, naRef me, int argc, naRef* args)
+{
+ Canvas* cvs = canvasGhost(me);
+ if (!cvs) {
+ naRuntimeError(c, "canvas.getElement called on non-canvas object");
+ }
+
+ return naNil();
+}
+
+static naRef f_element_addButtonCallback(naContext c, naRef me, int argc, naRef* args)
+{
+ canvas::Element* e = elementGhost(me);
+ if (!e) {
+ naRuntimeError(c, "element.addButtonCallback called on non-canvas-element object");
+ }
+
+ return naNil();
+}
+
+static naRef f_element_addDragCallback(naContext c, naRef me, int argc, naRef* args)
+{
+ canvas::Element* e = elementGhost(me);
+ if (!e) {
+ naRuntimeError(c, "element.addDragCallback called on non-canvas-element object");
+ }
+
+ return naNil();
+}
+
+static naRef f_element_addMoveCallback(naContext c, naRef me, int argc, naRef* args)
+{
+ canvas::Element* e = elementGhost(me);
+ if (!e) {
+ naRuntimeError(c, "element.addMoveCallback called on non-canvas-element object");
+ }
+
+ return naNil();
+}
+
+static naRef f_element_addScrollCallback(naContext c, naRef me, int argc, naRef* args)
+{
+ canvas::Element* e = elementGhost(me);
+ if (!e) {
+ naRuntimeError(c, "element.addScrollCallback called on non-canvas-element object");
+ }
+
+ return naNil();
+}
+
+static naRef f_canvas(naContext c, naRef me, int argc, naRef* args)
+{
+ return naNil();
+}
+
+// Table of extension functions. Terminate with zeros.
+static struct { const char* name; naCFunction func; } funcs[] = {
+ { "getCanvas", f_canvas },
+ { 0, 0 }
+};
+
+naRef initNasalCanvas(naRef globals, naContext c, naRef gcSave)
+{
+ canvasPrototype = naNewHash(c);
+ hashset(c, gcSave, "canvasProto", canvasPrototype);
+
+ hashset(c, canvasPrototype, "getElement", naNewFunc(c, naNewCCode(c, f_canvas_getElement)));
+
+ eventPrototype = naNewHash(c);
+ hashset(c, gcSave, "eventProto", eventPrototype);
+ // set any event methods
+
+ elementPrototype = naNewHash(c);
+ hashset(c, gcSave, "elementProto", elementPrototype);
+
+ hashset(c, elementPrototype, "addButtonCallback", naNewFunc(c, naNewCCode(c, f_element_addButtonCallback)));
+ hashset(c, elementPrototype, "addDragCallback", naNewFunc(c, naNewCCode(c, f_element_addDragCallback)));
+ hashset(c, elementPrototype, "addMoveCallback", naNewFunc(c, naNewCCode(c, f_element_addMoveCallback)));
+ hashset(c, elementPrototype, "addScrollCallback", naNewFunc(c, naNewCCode(c, f_element_addScrollCallback)));
+
+ for(int i=0; funcs[i].name; i++) {
+ hashset(c, globals, funcs[i].name,
+ naNewFunc(c, naNewCCode(c, funcs[i].func)));
+ }
+
+ return naNil();
+}
--- /dev/null
+// NasalCanvas.hxx -- expose Canvas classes to Nasal
+//
+// Written by James Turner, started 2012.
+//
+// Copyright (C) 2012 James Turner
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef SCRIPTING_NASAL_CANVAS_HXX
+#define SCRIPTING_NASAL_CANVAS_HXX
+
+#include <simgear/nasal/nasal.h>
+
+// forward decls
+namespace canvas
+{
+ class Element;
+}
+
+naRef initNasalCanvas(naRef globals, naContext c, naRef gcSave);
+
+#endif // of SCRIPTING_NASAL_CANVAS_HXX
+
continue;
}
- naRef nm = stringToNasal(c, park->getName());
- naVec_append(r, nm);
+ const SGGeod& parkLoc = park->getGeod();
+ naRef ph = naNewHash(c);
+ hashset(c, ph, "name", stringToNasal(c, park->getName()));
+ hashset(c, ph, "lat", naNum(parkLoc.getLatitudeDeg()));
+ hashset(c, ph, "lon", naNum(parkLoc.getLongitudeDeg()));
+ hashset(c, ph, "elevation", naNum(parkLoc.getElevationM()));
+ naVec_append(r, ph);
}
return r;
#include "NasalSys.hxx"
#include "NasalPositioned.hxx"
+#include "NasalCanvas.hxx"
+
#include <Main/globals.hxx>
#include <Main/util.hxx>
#include <Main/fg_props.hxx>
hashset(_globals, "__gcsave", _gcHash);
initNasalPositioned(_globals, _context, _gcHash);
+ initNasalCanvas(_globals, _context, _gcHash);
// Now load the various source files in the Nasal directory
simgear::Dir nasalDir(SGPath(globals->get_fg_root(), "Nasal"));
return naBindFunction(_context, code, _globals);
}
-bool FGNasalSys::handleCommand(const SGPropertyNode* arg)
+bool FGNasalSys::handleCommand( const char* moduleName,
+ const char* fileName,
+ const char* src,
+ const SGPropertyNode* arg )
{
- const char* nasal = arg->getStringValue("script");
- const char* moduleName = arg->getStringValue("module");
- naRef code = parse(arg->getPath(true).c_str(), nasal, strlen(nasal));
+ naRef code = parse(fileName, src, strlen(src));
if(naIsNil(code)) return false;
// Commands can be run "in" a module. Make sure that module
return true;
}
+bool FGNasalSys::handleCommand(const SGPropertyNode* arg)
+{
+ const char* src = arg->getStringValue("script");
+ const char* moduleName = arg->getStringValue("module");
+
+ return handleCommand( moduleName,
+ arg ? arg->getPath(true).c_str() : moduleName,
+ src,
+ arg );
+}
+
// settimer(func, dt, simtime) extension function. The first argument
// is a Nasal function to call, the second is a delta time (from now),
// in seconds. The third, if present, is a boolean value indicating
naRef cmdArgGhost();
// Callbacks for command and timer bindings
+ virtual bool handleCommand( const char* moduleName,
+ const char* fileName,
+ const char* src,
+ const SGPropertyNode* arg = 0 );
virtual bool handleCommand(const SGPropertyNode* arg);
bool createModule(const char* moduleName, const char* fileName,
// array. This allows the Nasal handlers to do things like:
// Node.getChild = func { _getChild(me.ghost, arg) }
//
-#define NODEARG() \
+#define NODENOARG() \
if(argc < 2 || !naIsGhost(args[0]) || \
naGhost_type(args[0]) != &PropNodeGhostType) \
naRuntimeError(c, "bad argument to props function"); \
- SGPropertyNode_ptr* node = (SGPropertyNode_ptr*)naGhost_ptr(args[0]); \
+ SGPropertyNode_ptr* node = (SGPropertyNode_ptr*)naGhost_ptr(args[0]);
+
+#define NODEARG() \
+ NODENOARG(); \
naRef argv = args[1]
static naRef f_getType(naContext c, naRef me, int argc, naRef* args)
{
using namespace simgear;
- NODEARG();
+ NODENOARG();
const char* t = "unknown";
switch((*node)->getType()) {
case props::NONE: t = "NONE"; break;
static naRef f_getName(naContext c, naRef me, int argc, naRef* args)
{
- NODEARG();
+ NODENOARG();
return NASTR((*node)->getName());
}
static naRef f_getIndex(naContext c, naRef me, int argc, naRef* args)
{
- NODEARG();
+ NODENOARG();
return naNum((*node)->getIndex());
}
static naRef f_getValue(naContext c, naRef me, int argc, naRef* args)
{
using namespace simgear;
- NODEARG();
+ NODENOARG();
switch((*node)->getType()) {
case props::BOOL: case props::INT:
case props::LONG: case props::FLOAT:
SG_LOG(SG_NASAL, SG_ALERT, "Nasal getValue: property " << (*node)->getPath() << " is NaN");
return naNil();
}
-
+
return naNum(dv);
}
-
+
case props::STRING:
case props::UNSPECIFIED:
return NASTR((*node)->getStringValue());
naRef n = naNumValue(val);
if(naIsNil(n))
naRuntimeError(c, "props.setValue() with non-number");
-
+
double d = naNumValue(val).num;
if (osg::isNaN(d)) {
naRuntimeError(c, "props.setValue() passed a NaN");
}
-
+
result = (*node)->setDoubleValue(d);
}
return naNum(result);
naRef r = naNumValue(naVec_get(argv, 0));
if (naIsNil(r))
naRuntimeError(c, "props.setDoubleValue() with non-number");
-
+
if (osg::isNaN(r.num)) {
naRuntimeError(c, "props.setDoubleValue() passed a NaN");
}
-
+
return naNum((*node)->setDoubleValue(r.num));
}
static naRef f_getParent(naContext c, naRef me, int argc, naRef* args)
{
- NODEARG();
+ NODENOARG();
SGPropertyNode* n = (*node)->getParent();
if(!n) return naNil();
return propNodeGhostCreate(c, n);
static naRef f_unalias(naContext c, naRef me, int argc, naRef* args)
{
- NODEARG();
+ NODENOARG();
return naNum((*node)->unalias());
}
static naRef f_getAliasTarget(naContext c, naRef me, int argc, naRef* args)
{
- NODEARG();
+ NODENOARG();
return propNodeGhostCreate(c, (*node)->getAliasTarget());
}
if (!_classicalRenderer) {
eventHandler->setChangeStatsCameraRenderOrder( true );
+ _sky->set_minimum_sky_visibility( 0.0 ); // A black sky appears for below that
}
}
ss->addUniform( _shadowDistances );
ss->addUniform( _fogColor );
ss->addUniform( _fogDensity );
- ss->addUniform( _planes );
osg::Geometry* g = osg::createTexturedQuadGeometry( osg::Vec3(-1.,-1.,0.), osg::Vec3(2.,0.,0.), osg::Vec3(0.,2.,0.) );
g->setUseDisplayList(false);
}
void
-FGRenderer::buildDeferredDisplayCamera( osg::Camera* camera, flightgear::CameraInfo* info, const std::string& name, osg::GraphicsContext* gc )
+FGRenderer::buildDeferredDisplayCamera( osg::Camera* camera, flightgear::CameraInfo* info, const FGRenderingPipeline::Stage* stage, osg::GraphicsContext* gc )
{
camera->setName( "DisplayC" );
- camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( name, info ) );
+ camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( stage->name, info ) );
camera->setReferenceFrame(Transform::ABSOLUTE_RF);
camera->setAllowEventFocus(false);
osg::Geometry* g = osg::createTexturedQuadGeometry( osg::Vec3(-1.,-1.,0.), osg::Vec3(2.,0.,0.), osg::Vec3(0.,2.,0.) );
g->setUseDisplayList(false); //DEBUG
simgear::EffectGeode* eg = new simgear::EffectGeode;
- simgear::Effect* effect = simgear::makeEffect("Effects/display", true);
+ simgear::Effect* effect = simgear::makeEffect(stage->effect, true);
if (!effect) {
- SG_LOG(SG_VIEW, SG_ALERT, "Effects/display not found");
+ SG_LOG(SG_VIEW, SG_ALERT, stage->effect + " not found");
return;
}
eg->setEffect(effect);
osg::StateSet* ss = camera->getOrCreateStateSet();
ss->addUniform( _depthInColor );
+ ss->addUniform( info->bufferSize );
}
void
camera = buildDeferredFullscreenCamera(info, gc, stage);
else if (stage->type == "display") {
camera = mainCamera;
- buildDeferredDisplayCamera(camera, info, stage->name, gc);
+ buildDeferredDisplayCamera(camera, info, stage, gc);
} else
throw sg_exception("Stage type is not supported");
StateSet* ss = lightCam->getOrCreateStateSet();
ss->addUniform( _planes );
ss->addUniform( info->bufferSize );
+ ss->addUniform( _fogColor );
+ ss->addUniform( _fogDensity );
lightCam->setName( "LightCamera" );
lightCam->setClearMask(0);
lightCam->setAllowEventFocus(false);
osg::Camera* buildDeferredLightingCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc, const FGRenderingPipeline::Stage* stage );
osg::Camera* buildDeferredFullscreenCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc, const FGRenderingPipeline::Stage* stage );
osg::Camera* buildDeferredFullscreenCamera( flightgear::CameraInfo* info, const FGRenderingPipeline::Pass* pass );
- void buildDeferredDisplayCamera( osg::Camera* camera, flightgear::CameraInfo* info, const std::string& name, osg::GraphicsContext* gc );
+ void buildDeferredDisplayCamera( osg::Camera* camera, flightgear::CameraInfo* info, const FGRenderingPipeline::Stage* stage, osg::GraphicsContext* gc );
void updateShadowCascade(const flightgear::CameraInfo* info, osg::Camera* camera, osg::Group* grp, int idx, double left, double right, double bottom, double top, double zNear, double f1, double f2);
osg::Vec3 getSunDirection() const;
#ifdef HAVE_CONFIG_H
# include <config.h>
-#endif
+#endif
#include <simgear/compiler.h>
MIDGTrack::~MIDGTrack() {};
-
-
+/*
+ * Unused function
+ */
+#if(0)
static uint32_t read_swab( char *buf, size_t offset, size_t size ) {
uint32_t result = 0;
return result;
}
+#endif
static bool validate_cksum( uint8_t id, uint8_t size, char *buf,
void MIDGTrack::parse_msg( const int id, char *buf, MIDGpos *pos, MIDGatt *att )
{
+/*
+ * Completely unused parser results. Removed from compiling to remove the warnings
+ */
+#if(0)
if ( id == 1 ) {
uint32_t ts;
uint16_t status;
// timestamp
ts = (uint32_t)read_swab( buf, 0, 4 );
// cout << " time stamp = " << ts << endl;
-
+
// status
status = (uint16_t)read_swab( buf, 4, 2 );
// cout << " status = " << status << endl;
// position dop
pdop = (uint16_t)read_swab( buf, 32, 2 );
// cout << " pdop = " << pdop << endl;
-
+
// position accuracy
pacc = (uint16_t)read_swab( buf, 34, 2 );
// cout << " pacc = " << pacc << endl;
-
+
// speed accuracy
sacc = (uint16_t)read_swab( buf, 36, 2 );
// cout << " sacc = " << sacc << endl;
-
+
} else {
cout << "unknown id = " << id << endl;
}
+#endif
}
// read checksum
myread( ch, log, tmpbuf, 1 ); uint8_t cksum0 = (unsigned char)tmpbuf[0];
myread( ch, log, tmpbuf, 1 ); uint8_t cksum1 = (unsigned char)tmpbuf[0];
-
+
if ( validate_cksum( id, size, savebuf, cksum0, cksum1 ) ) {
parse_msg( id, savebuf, pos, att );
return id;
{
char tmpbuf[256];
char savebuf[256];
- int result = 0;
cout << "in next_message()" << endl;
// scan for sync characters
uint8_t sync0, sync1;
- result = serial_read( serial, tmpbuf, 2 );
+ serial_read( serial, tmpbuf, 2 );
sync0 = (unsigned char)tmpbuf[0];
sync1 = (unsigned char)tmpbuf[1];
while ( (sync0 != 129 || sync1 != 161) && !myeof ) {
serial_read( serial, tmpbuf, 2 );
uint8_t cksum0 = (unsigned char)tmpbuf[0];
uint8_t cksum1 = (unsigned char)tmpbuf[1];
-
+
if ( validate_cksum( id, size, savebuf, cksum0, cksum1 ) ) {
parse_msg( id, savebuf, pos, att );
cout << "Check sum failure!" << endl;
return -1;
-
+
}
// point value. By doing the BIG_ENDIAN test, I can optimize the
// routine for big-endian processors so it can be as efficient as
// possible
-static void htond (double &x)
+static void htond (double &x)
{
if ( sgIsLittleEndian() ) {
int *Double_Overlay;
int Holding_Buffer;
-
+
Double_Overlay = (int *) &x;
Holding_Buffer = Double_Overlay [0];
-
+
Double_Overlay [0] = htonl (Double_Overlay [1]);
Double_Overlay [1] = htonl (Holding_Buffer);
} else {
}
// Float version
-static void htonf (float &x)
+static void htonf (float &x)
{
if ( sgIsLittleEndian() ) {
int *Float_Overlay;
int Holding_Buffer;
-
+
Float_Overlay = (int *) &x;
Holding_Buffer = Float_Overlay [0];
-
+
Float_Overlay [0] = htonl (Holding_Buffer);
} else {
return;
static void send_data( const MIDGpos pos, const MIDGatt att ) {
- int len;
int fdmsize = sizeof( FGNetFDM );
- // cout << "Running main loop" << endl;
-
FGNetFDM fgfdm;
FGNetCtrls fgctrls;
midg2fg( pos, att, &fgfdm, &fgctrls );
- len = fdm_sock.send(&fgfdm, fdmsize, 0);
+ fdm_sock.send(&fgfdm, fdmsize, 0);
}
MIDGpos pos0, pos1;
pos0 = pos1 = track.get_pospt( 0 );
-
+
MIDGatt att0, att1;
att0 = att1 = track.get_attpt( 0 );
-
+
while ( current_time < end_time ) {
// cout << "current_time = " << current_time << " end_time = "
// << end_time << endl;
// process incoming data from the serial port
int count = 0;
- double current_time = 0.0;
MIDGpos pos;
MIDGatt att;
if ( id == 10 ) {
if ( att.get_msec() > att_time ) {
att_time = att.get_msec();
- current_time = att_time;
+ //current_time = att_time;
} else {
cout << "oops att back in time" << endl;
}
} else if ( id == 12 ) {
if ( pos.get_msec() > pos_time ) {
pos_time = pos.get_msec();
- current_time = pos_time;
+ //current_time = pos_time;
} else {
cout << "oops pos back in time" << endl;
}
#ifdef HAVE_CONFIG_H
# include <config.h>
-#endif
+#endif
#include <iostream>
#include <cstdio>
myread( ch, log, tmpbuf, 2 );
uint8_t cksum0 = (unsigned char)tmpbuf[0];
uint8_t cksum1 = (unsigned char)tmpbuf[1];
-
+
if ( validate_cksum( id, size, savebuf, cksum0, cksum1, ignore_checksum ) )
{
parse_msg( id, savebuf, gpspacket, imupacket, navpacket, servopacket,
{
char tmpbuf[256];
char savebuf[256];
- int result = 0;
// cout << "in next_message()" << endl;
// scan for sync characters
int scan_count = 0;
uint8_t sync0, sync1;
- result = serial_read( serial, log, tmpbuf, 2 );
+ serial_read( serial, log, tmpbuf, 2 );
sync0 = (unsigned char)tmpbuf[0];
sync1 = (unsigned char)tmpbuf[1];
while ( (sync0 != START_OF_MSG0 || sync1 != START_OF_MSG1) && !myeof ) {
uint8_t cksum1 = (unsigned char)tmpbuf[1];
// cout << "cksum0 = " << (int)cksum0 << " cksum1 = " << (int)cksum1
// << endl;
-
+
if ( validate_cksum( id, size, savebuf, cksum0, cksum1, ignore_checksum ) )
{
parse_msg( id, savebuf, gpspacket, imupacket, navpacket, servopacket,
cout << "Check sum failure!" << endl;
return -1;
-
+
}
// point value. By doing the BIG_ENDIAN test, I can optimize the
// routine for big-endian processors so it can be as efficient as
// possible
-static void htond (double &x)
+static void htond (double &x)
{
if ( sgIsLittleEndian() ) {
int *Double_Overlay;
int Holding_Buffer;
-
+
Double_Overlay = (int *) &x;
Holding_Buffer = Double_Overlay [0];
-
+
Double_Overlay [0] = htonl (Double_Overlay [1]);
Double_Overlay [1] = htonl (Holding_Buffer);
} else {
}
// Float version
-static void htonf (float &x)
+static void htonf (float &x)
{
if ( sgIsLittleEndian() ) {
int *Float_Overlay;
int Holding_Buffer;
-
+
Float_Overlay = (int *) &x;
Holding_Buffer = Float_Overlay [0];
-
+
Float_Overlay [0] = htonl (Holding_Buffer);
} else {
return;
htonf(fdm->speedbrake);
htonf(fdm->spoilers);
-#if 0
+#if 0
ctrls->version = FG_NET_CTRLS_VERSION;
ctrls->elevator_trim = 0.0;
ctrls->flaps = 0.0;
static void send_data_udp( gps *gpspacket, imu *imupacket, nav *navpacket,
servo *servopacket, health *healthpacket )
{
- int len;
int ogcsize = sizeof( ogcFGData );
int fdmsize = sizeof( FGNetFDM );
// int ctrlsize = sizeof( FGNetCtrls );
&fgfdm, &fgctrls );
ugear2opengc( gpspacket, imupacket, navpacket, servopacket, healthpacket,
&fgogc );
- len = opengc_sock.send(&fgogc, ogcsize, 0);
- len = fdm_sock.send(&fgfdm, fdmsize, 0);
+ opengc_sock.send(&fgogc, ogcsize, 0);
+ fdm_sock.send(&fgfdm, fdmsize, 0);
// len = ctrls_sock.send(&fgctrls, ctrlsize, 0);
}
gps gps0, gps1;
gps0 = gps1 = track.get_gpspt( 0 );
-
+
imu imu0, imu1;
imu0 = imu1 = track.get_imupt( 0 );
-
+
nav nav0, nav1;
nav0 = nav1 = track.get_navpt( 0 );
-
+
servo servo0, servo1;
servo0 = servo1 = track.get_servopt( 0 );
-
+
health health0, health1;
health0 = health1 = track.get_healthpt( 0 );
} else {
cout << "oops health back in time: " << healthpacket.time << " " << health_time << endl;
}
-
+
}
if ( (current_time > gps_time + 2) ||
command_mgr.add("hb");
command_heartbeat = current_time;
}
-
+
// Command update @ 1hz
if ( current_time >= command_time + 1 ) {
command_mgr.update(&uavcom);
// double lonmin = fabs(navpacket.lon - londeg);
int latdeg = (int)navpacket.lat;
// double latmin = fabs(navpacket.lat - latdeg);
- char londir = 'E'; if ( londeg < 0 ) londir = 'W';
- char latdir = 'N'; if ( latdeg < 0 ) latdir = 'S';
londeg = abs(londeg);
latdeg = abs(latdeg);
/*printf( "%.2f %c%02d:%.4f %c%03d:%.4f %.1f %.2f %.2f %.2f\n",
// point value. By doing the BIG_ENDIAN test, I can optimize the
// routine for big-endian processors so it can be as efficient as
// possible
-static void htond (double &x)
+static void htond (double &x)
{
if ( sgIsLittleEndian() ) {
int *Double_Overlay;
int Holding_Buffer;
-
+
Double_Overlay = (int *) &x;
Holding_Buffer = Double_Overlay [0];
-
+
Double_Overlay [0] = htonl (Double_Overlay [1]);
Double_Overlay [1] = htonl (Holding_Buffer);
} else {
}
// Float version
-static void htonf (float &x)
+static void htonf (float &x)
{
if ( sgIsLittleEndian() ) {
int *Float_Overlay;
int Holding_Buffer;
-
+
Float_Overlay = (int *) &x;
Holding_Buffer = Float_Overlay [0];
-
+
Float_Overlay [0] = htonl (Holding_Buffer);
} else {
return;
static void send_data( const GPSPoint p ) {
- int len;
// int ctrlsize = sizeof( FGNetCtrls );
int fdmsize = sizeof( FGNetFDM );
FGNetCtrls fgctrls;
gps2fg( p, &fgfdm, &fgctrls );
- len = fdm_sock.send(&fgfdm, fdmsize, 0);
+ fdm_sock.send(&fgfdm, fdmsize, 0);
}
GPSPoint p, p0, p1;
p0 = p1 = track.get_point( 0 );
-
+
while ( current_time < end_time ) {
// cout << "current_time = " << current_time << " end_time = "
// << end_time << endl;
{ "HELVETICA_10", &PUFONT_HELVETICA_10 },
{ "HELVETICA_12", &PUFONT_HELVETICA_12 },
// { "HELVETICA_14", &FONT_HELVETICA_14 },
- { "HELVETICA_18", &PUFONT_HELVETICA_18 }
-// { "SANS_12B", &FONT_SANS_12B }
+ { "HELVETICA_18", &PUFONT_HELVETICA_18 },
+// { "SANS_12B", &FONT_SANS_12B },
+ { 0 }
};
-const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])];
+const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])-1];
}
FGFontCache::fnt::~fnt()
// fgviewer.cxx -- alternative flightgear viewer application
//
-// Copyright (C) 2009 - 2011 Mathias Froehlich
+// Copyright (C) 2009 - 2012 Mathias Froehlich
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
-#include <simgear/misc/sg_path.hxx>
#include <simgear/scene/material/EffectCullVisitor.hxx>
#include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/scene/util/SGSceneFeatures.hxx>
-#include <simgear/scene/util/SGUpdateVisitor.hxx>
#include <simgear/scene/tgdb/userdata.hxx>
#include <simgear/scene/model/ModelRegistry.hxx>
-#include <simgear/scene/model/modellib.hxx>
+#include <simgear/misc/ResourceManager.hxx>
int
main(int argc, char** argv)
{
+ /// Read arguments and environment variables.
+
// use an ArgumentParser object to manage the program arguments.
+ // FIXME implement a flightgear similar argument parser into simgear and use this one
osg::ArgumentParser arguments(&argc, argv);
std::string fg_root;
// In case of an error, at least make summer :)
props->getNode("sim/startup/season", true)->setStringValue("summer");
- std::cerr << "Problems loading FlightGear preferences.\n"
- << "Probably FG_ROOT is not properly set." << std::endl;
+ SG_LOG(SG_GENERAL, SG_ALERT, "Problems loading FlightGear preferences.\n"
+ << "Probably FG_ROOT is not properly set.");
}
std::string config;
try {
readProperties(config, props);
} catch (...) {
- std::cerr << "Problems loading config file \"" << config
- << "\" given on the command line." << std::endl;
+ SG_LOG(SG_GENERAL, SG_ALERT, "Problems loading config file \"" << config
+ << "\" given on the command line.");
}
}
props->setStringValue(prop, value);
}
- // Just reference simgears reader writer stuff so that the globals get
- // pulled in by the linker ...
- // FIXME: make that more explicit clear and call an initialization function
- simgear::ModelRegistry::instance();
+ /// Start setting up the viewer windows and start feeding them.
// construct the viewer.
osgViewer::Viewer viewer(arguments);
osgUtil::SceneView* sceneView = renderer->getSceneView(j);
sceneView->setCullVisitor(new simgear::EffectCullVisitor);
}
- // Shaders expect valid fog
- osg::Fog* fog = new osg::Fog;
- fog->setMode(osg::Fog::EXP2);
- fog->setColor(osg::Vec4(1, 1, 1, 1));
- fog->setDensity(1e-6);
- camera->getOrCreateStateSet()->setAttribute(fog);
+ // We want on demand database paging
+ viewer.setDatabasePager(new osgDB::DatabasePager);
+ viewer.getDatabasePager()->setUpThreads(1, 1);
+
+ /// now set up the simgears required model stuff
+
+ simgear::ResourceManager::instance()->addBasePath(fg_root, simgear::ResourceManager::PRIORITY_DEFAULT);
+ // Just reference simgears reader writer stuff so that the globals get
+ // pulled in by the linker ...
+ // FIXME: make that more explicit clear and call an initialization function
+ simgear::ModelRegistry::instance();
+
+ // FIXME Ok, replace this by querying the root of the property tree
sgUserDataInit(props.get());
SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::DoNotUseCompression);
SGMaterialLib* ml = new SGMaterialLib;
SGPath mpath(fg_root);
- mpath.append("materials.xml");
+ mpath.append("Materials/default/materials.xml");
try {
ml->load(fg_root, mpath.str(), props);
} catch (...) {
- std::cerr << "Problems loading FlightGear materials.\n"
- << "Probably FG_ROOT is not properly set." << std::endl;
+ SG_LOG(SG_GENERAL, SG_ALERT, "Problems loading FlightGear materials.\n"
+ << "Probably FG_ROOT is not properly set.");
}
simgear::SGModelLib::init(fg_root, props);
options->setMaterialLib(ml);
options->setPropertyNode(props);
options->setPluginStringData("SimGear::FG_ROOT", fg_root);
- // We have some problems here, rethink them at some time
- options->setPluginStringData("SimGear::PARTICLESYSTEM", "OFF");
// Omit building bounding volume trees, as the viewer will not run a simulation
options->setPluginStringData("SimGear::BOUNDINGVOLUMES", "OFF");
arguments.reportRemainingOptionsAsUnrecognized();
arguments.writeErrorMessages(std::cerr);
+
+ /// Read the model files that are configured.
+
osg::ref_ptr<osg::Node> loadedModel;
- if (arguments.argc() != 1) {
+ if (1 < arguments.argc()) {
// read the scene from the list of file specified command line args.
loadedModel = osgDB::readNodeFiles(arguments, options.get());
} else {
// if no model has been successfully loaded report failure.
if (!loadedModel.valid()) {
- std::cerr << arguments.getApplicationName()
- << ": No data loaded" << std::endl;
+ SG_LOG(SG_GENERAL, SG_ALERT, arguments.getApplicationName()
+ << ": No data loaded");
return EXIT_FAILURE;
}
// pass the loaded scene graph to the viewer.
viewer.setSceneData(loadedModel.get());
- // We want on demand database paging
- viewer.setDatabasePager(new osgDB::DatabasePager);
- viewer.getDatabasePager()->setUpThreads(1, 1);
-
return viewer.run();
}