]> git.mxchange.org Git - flightgear.git/commitdiff
Merge branch 'timoore/optimization' into next
authorTim Moore <timoore33@gmail.com>
Fri, 3 Aug 2012 18:20:01 +0000 (20:20 +0200)
committerTim Moore <timoore33@gmail.com>
Fri, 3 Aug 2012 18:20:01 +0000 (20:20 +0200)
76 files changed:
.gitignore
CMakeLists.txt
package/Win-NSIS/flightgear64-nightly-vs2010.nsi [new file with mode: 0644]
src/ATCDCL/ATC.cxx
src/ATCDCL/ATC.hxx
src/ATCDCL/ATISmgr.cxx
src/ATCDCL/ATISmgr.hxx
src/ATCDCL/atis.cxx
src/ATCDCL/atis.hxx
src/Autopilot/functor.hxx
src/Canvas/CMakeLists.txt
src/Canvas/MouseEvent.hxx [new file with mode: 0644]
src/Canvas/canvas.cxx
src/Canvas/canvas.hxx
src/Canvas/canvas_fwd.hpp [new file with mode: 0644]
src/Canvas/canvas_mgr.cxx
src/Canvas/canvas_mgr.hxx
src/Canvas/elements/element.cxx
src/Canvas/elements/group.cxx
src/Canvas/elements/map.cxx [new file with mode: 0644]
src/Canvas/elements/map.hxx [new file with mode: 0644]
src/Canvas/elements/map/geo_node_pair.hxx [new file with mode: 0644]
src/Canvas/elements/map/projection.hxx [new file with mode: 0644]
src/Canvas/elements/path.cxx
src/Canvas/elements/text.cxx
src/Canvas/elements/text.hxx
src/Canvas/gui_mgr.cxx [new file with mode: 0644]
src/Canvas/gui_mgr.hxx [new file with mode: 0644]
src/Canvas/placement.cxx [new file with mode: 0644]
src/Canvas/placement.hxx [new file with mode: 0644]
src/Canvas/property_based_element.cxx [new file with mode: 0644]
src/Canvas/property_based_element.hxx [new file with mode: 0644]
src/Canvas/property_based_mgr.cxx [new file with mode: 0644]
src/Canvas/property_based_mgr.hxx [new file with mode: 0644]
src/Canvas/property_helper.cxx
src/Canvas/property_helper.hxx
src/Canvas/rect.hxx [new file with mode: 0644]
src/Canvas/window.cxx [new file with mode: 0644]
src/Canvas/window.hxx [new file with mode: 0644]
src/FDM/JSBSim/models/FGPropulsion.cpp
src/GUI/CMakeLists.txt
src/GUI/CanvasWidget.cxx [new file with mode: 0644]
src/GUI/CanvasWidget.hxx [new file with mode: 0644]
src/GUI/FGFontCache.cxx
src/GUI/FGPUIDialog.cxx
src/GUI/new_gui.cxx
src/Instrumentation/adf.cxx
src/Instrumentation/adf.hxx
src/Instrumentation/instrument_mgr.cxx
src/Instrumentation/navradio.cxx
src/Instrumentation/od_gauge.cxx
src/Instrumentation/od_gauge.hxx
src/Instrumentation/wxradar.cxx
src/Main/fg_commands.cxx
src/Main/fg_init.cxx
src/Main/metar_main.cxx
src/Model/modelmgr.cxx
src/Network/HLA/hla.cxx
src/Scenery/tilemgr.cxx
src/Scripting/CMakeLists.txt
src/Scripting/NasalCanvas.cxx [new file with mode: 0644]
src/Scripting/NasalCanvas.hxx [new file with mode: 0644]
src/Scripting/NasalPositioned.cxx
src/Scripting/NasalSys.cxx
src/Scripting/NasalSys.hxx
src/Scripting/nasal-props.cxx
src/Viewer/renderer.cxx
src/Viewer/renderer.hxx
utils/GPSsmooth/MIDG-II.cxx
utils/GPSsmooth/MIDG_main.cxx
utils/GPSsmooth/UGear.cxx
utils/GPSsmooth/UGear_main.cxx
utils/GPSsmooth/gps_main.cxx
utils/fgpanel/FGFontCache.cxx
utils/fgviewer/fgviewer.cxx
version

index 8a18462566b4bfeb480783a37832429f89ed5ed5..04012e7e865a80b413a284cd585459b466a17bdc 100644 (file)
@@ -1,3 +1,4 @@
+.*
 Makefile
 Debug/
 Build
index 3549c89eaf45dcce7e6d29a13afb738a1978561b..150c3931d276e7e571aec0c9a53ff2081529107d 100644 (file)
@@ -18,6 +18,14 @@ else(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
     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")
diff --git a/package/Win-NSIS/flightgear64-nightly-vs2010.nsi b/package/Win-NSIS/flightgear64-nightly-vs2010.nsi
new file mode 100644 (file)
index 0000000..f8d03de
--- /dev/null
@@ -0,0 +1,153 @@
+!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
index 0f0e0f9e4973aa0f4b2c4e4de87900bc045e20fb..5e03ca38308419a2dfc0895befd876ad90251376 100644 (file)
@@ -77,7 +77,7 @@ FGATC::~FGATC() {
 #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() ||
@@ -117,7 +117,7 @@ void FGATC::SetStation(flightgear::CommStation* sta) {
         freq = 0;
 
         SetNoDisplay();
-        Update(0);     // one last update
+        update(0);     // one last update
     }
     else
     {
index f709c1dcc41dbe33fe791077caeecbcc911cdca6..e57ebabd7d8a245df0606164c2bfbe4f8d8af7b6 100644 (file)
@@ -90,17 +90,17 @@ std::ostream& operator << (std::ostream& os, atc_type atc);
 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; }
        
@@ -141,7 +141,7 @@ public:
        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; }
index 0df65051e8bb95b402805172d01ed3d0c82d7057..1c5dc8ca7936dc2a23b40219ce2f8009dacc2341 100644 (file)
 #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);
@@ -56,58 +49,36 @@ FGATISMgr::~FGATISMgr()
 
     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
@@ -119,13 +90,13 @@ void FGATISMgr::update(double dt)
 // 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
@@ -135,22 +106,19 @@ FGATCVoice* FGATISMgr::GetVoicePointer(const atc_type& type)
              *  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:
@@ -161,52 +129,7 @@ FGATCVoice* FGATISMgr::GetVoicePointer(const atc_type& type)
             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);
-}
index 75ef3a30f98ef255b98742ca054714c4515423c2..716044f83fdc3a59f8aa4426df0165154180023c 100644 (file)
 // 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:
@@ -75,11 +47,6 @@ 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
@@ -92,8 +59,6 @@ public:
     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
index 95acc757b3dd33e01b05270faa915cd77fcd3465..36f2f66f03708b412efe629574e8abd08f60f847 100644 (file)
@@ -55,6 +55,7 @@
 #include <Airports/runways.hxx>
 #include <Airports/dynamics.hxx>
 
+#include <ATC/CommStation.hxx>
 
 #include "ATCutils.hxx"
 #include "ATISmgr.hxx"
@@ -65,8 +66,11 @@ using std::cout;
 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),
@@ -74,10 +78,37 @@ FGATIS::FGATIS(const string& commbase) :
   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 ...
@@ -115,7 +146,7 @@ FGATCVoice* FGATIS::GetVoicePointer()
     return pAtisMgr->GetVoicePointer(ATIS);
 }
 
-void FGATIS::Init() {
+void FGATIS::init() {
 // Nothing to see here.  Move along.
 }
 
@@ -134,7 +165,7 @@ FGATIS::attend (int attn)
 
 
 // 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);
 
@@ -148,28 +179,52 @@ void FGATIS::Update(double dt) {
   }
 #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;
 }
 
@@ -522,10 +577,74 @@ int FGATIS::GenTransmission(const int regen, const int special) {
 // 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.");
+    }
+}
index 8a79e9fb28d5f08400504dc59cb1224b01521d8d..bd67d8ec8be2df1712c1c1fda4744e310e4edee5 100644 (file)
 
 #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& );
 
 };
 
index 2f1ac36dfa2f18d8276248cc8f26fca09a184ba3..4b1fda6f0a0bf89ee800483f2a36dfe734920097 100644 (file)
@@ -31,6 +31,7 @@ namespace FGXMLAutopilot {
 
 template <class TBase> class FunctorBase {
 public:
+  virtual ~FunctorBase() {}
   virtual TBase * operator()( SGPropertyNode_ptr configNode ) = 0;
 };
 
index 6927c04a4b510d5b03ba4984dcecbec376e19b12..d8c45bde1be02d4fc2a8eaff7fa514984993d653 100644 (file)
@@ -5,9 +5,15 @@ set(SOURCES
   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
@@ -15,9 +21,15 @@ 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}")
diff --git a/src/Canvas/MouseEvent.hxx b/src/Canvas/MouseEvent.hxx
new file mode 100644 (file)
index 0000000..0bd5d44
--- /dev/null
@@ -0,0 +1,53 @@
+// 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_ */
index 7f2c8590296ccd1883ea5d7db38a6045ae0c4918..d379b644d4128691b2935d426b41143bd3ce236a 100644 (file)
 
 #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)
-    );
-  }
 }
 
 //------------------------------------------------------------------------------
@@ -244,16 +181,33 @@ void Canvas::update(double delta_time_sec)
       // 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();
 }
 
 //------------------------------------------------------------------------------
@@ -274,12 +228,6 @@ void Canvas::setSizeX(int sx)
   setStatusFlags(CREATE_FAILED, false);
 }
 
-//------------------------------------------------------------------------------
-int Canvas::getSizeX() const
-{
-  return _size_x;
-}
-
 //------------------------------------------------------------------------------
 void Canvas::setSizeY(int sy)
 {
@@ -298,12 +246,6 @@ void Canvas::setSizeY(int sy)
   setStatusFlags(CREATE_FAILED, false);
 }
 
-//------------------------------------------------------------------------------
-int Canvas::getSizeY() const
-{
-  return _size_y;
-}
-
 //------------------------------------------------------------------------------
 void Canvas::setViewWidth(int w)
 {
@@ -314,12 +256,6 @@ void Canvas::setViewWidth(int w)
   _texture.setViewSize(_view_width, _view_height);
 }
 
-//------------------------------------------------------------------------------
-int Canvas::getViewWidth() const
-{
-  return _view_width;
-}
-
 //------------------------------------------------------------------------------
 void Canvas::setViewHeight(int h)
 {
@@ -331,15 +267,19 @@ 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;
 }
 
 //------------------------------------------------------------------------------
@@ -364,7 +304,7 @@ void Canvas::childRemoved( SGPropertyNode * parent,
     return;
 
   if( child->getNameString() == "placement" )
-    clearPlacements(child->getIndex());
+    _placements[ child->getIndex() ].clear();
   else
     static_cast<canvas::Element*>(_root_group.get())
       ->childRemoved(parent, child);
@@ -373,6 +313,9 @@ void Canvas::childRemoved( SGPropertyNode * parent,
 //----------------------------------------------------------------------------
 void Canvas::valueChanged(SGPropertyNode* node)
 {
+  if( boost::starts_with(node->getNameString(), "status") )
+    return;
+
   if( node->getParent()->getParent() == _node )
   {
     if(    !_color_background.empty()
@@ -398,18 +341,96 @@ void Canvas::valueChanged(SGPropertyNode* node)
         || 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";
@@ -426,47 +447,4 @@ void Canvas::setStatusFlags(unsigned int flags, bool set)
 }
 
 //------------------------------------------------------------------------------
-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;
index 25f87012d3c98fafc3226093a3b6bfc90c7c4836..29d9ee93e04d368bfb9af56fde5d71b3f2d8b2e5 100644 (file)
 #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:
 
@@ -44,26 +44,64 @@ class Canvas:
       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 );
@@ -71,6 +109,15 @@ class Canvas:
                                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;
@@ -81,8 +128,16 @@ class Canvas:
         _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;
@@ -90,19 +145,19 @@ class Canvas:
     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_ */
diff --git a/src/Canvas/canvas_fwd.hpp b/src/Canvas/canvas_fwd.hpp
new file mode 100644 (file)
index 0000000..c56612f
--- /dev/null
@@ -0,0 +1,53 @@
+// 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_ */
index 72db55fd0dea11c6f4d6fff7f3818e14a6909baa..21fcccf80f676ebc6b2dac5d492bc379898d4852 100644 (file)
 #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();
 }
index 893b50e887e7fc77c094671034e27518611bbfef..10cbe9a764a6bae20fd9463d215c36fe4447c822 100644 (file)
 #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_ */
index 3c2cdc64b386e69d242c22a5fd03c4be4dfe4b01..b01b36966c473d89d35375358cb23973b87609b7 100644 (file)
@@ -40,6 +40,10 @@ namespace canvas
   //----------------------------------------------------------------------------
   void Element::update(double dt)
   {
+    if( !_transform->getNodeMask() )
+      // Don't do anything if element is hidden
+      return;
+
     if( _transform_dirty )
     {
       osg::Matrix m;
@@ -159,13 +163,6 @@ namespace canvas
         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;
     }
@@ -208,6 +205,9 @@ namespace canvas
     {
       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);
     }
index ebbe3e6f747589295db4dc5b9e2730458976d57d..96eb49c23563518fd531ffa2757b57dfc7a9e44e 100644 (file)
@@ -17,6 +17,7 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
 #include "group.hxx"
+#include "map.hxx"
 #include "path.hxx"
 #include "text.hxx"
 
@@ -56,6 +57,8 @@ namespace canvas
       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) );
 
@@ -72,7 +75,8 @@ namespace canvas
   {
     if(    node->getNameString() == "text"
         || node->getNameString() == "group"
-        || node->getNameString() == "path")
+        || node->getNameString() == "map"
+        || node->getNameString() == "path" )
     {
       ChildMap::iterator child = _children.find(node);
 
diff --git a/src/Canvas/elements/map.cxx b/src/Canvas/elements/map.cxx
new file mode 100644 (file)
index 0000000..59a7d9b
--- /dev/null
@@ -0,0 +1,232 @@
+// 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
diff --git a/src/Canvas/elements/map.hxx b/src/Canvas/elements/map.hxx
new file mode 100644 (file)
index 0000000..944f8b6
--- /dev/null
@@ -0,0 +1,77 @@
+// 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_ */
diff --git a/src/Canvas/elements/map/geo_node_pair.hxx b/src/Canvas/elements/map/geo_node_pair.hxx
new file mode 100644 (file)
index 0000000..14a04c9
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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_ */
diff --git a/src/Canvas/elements/map/projection.hxx b/src/Canvas/elements/map/projection.hxx
new file mode 100644 (file)
index 0000000..446230e
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * 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_ */
index a002f509b6859d40f0158626ed1c16a50c6424d6..63b34f17000907e3028835131c4d9fbe3b83fcd0 100644 (file)
@@ -41,6 +41,7 @@ namespace canvas
         _paint_fill(VG_INVALID_HANDLE),
         _attributes_dirty(~0),
         _stroke_width(1),
+        _stroke_linecap(VG_CAP_BUTT),
         _fill(false)
       {
         setSupportsDisplayList(false);
@@ -114,6 +115,21 @@ namespace canvas
         _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
        */
@@ -175,6 +191,7 @@ namespace canvas
           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] );
@@ -244,6 +261,7 @@ namespace canvas
       VGfloat               _stroke_color[4];
       VGfloat               _stroke_width;
       std::vector<VGfloat>  _stroke_dash;
+      VGCapStyle            _stroke_linecap;
 
       bool      _fill;
       VGfloat   _fill_color[4];
@@ -371,6 +389,8 @@ namespace canvas
     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() );
   }
index dd23e921fc7ce9c7962be660430c44e6662e568b..518e7837881869e0b38d2545bff6ae3f87e600ce 100644 (file)
 
 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 )
   {
@@ -41,54 +126,12 @@ namespace canvas
 
     _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;
+
   }
 
   //----------------------------------------------------------------------------
@@ -125,10 +168,20 @@ namespace canvas
 #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() )
@@ -142,16 +195,40 @@ namespace canvas
         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() );
   }
 
   //----------------------------------------------------------------------------
@@ -166,6 +243,14 @@ namespace canvas
     _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)
   {
index 38c7f13350d6a401502db15dc8f9ccf79a2c3cb4..630e717cfddadb6bf5335b702e292bd9dcf0cc9b 100644 (file)
@@ -33,14 +33,12 @@ namespace canvas
   {
     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:
 
@@ -49,7 +47,8 @@ namespace canvas
         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;
@@ -58,6 +57,8 @@ namespace canvas
       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);
   };
diff --git a/src/Canvas/gui_mgr.cxx b/src/Canvas/gui_mgr.cxx
new file mode 100644 (file)
index 0000000..6ff2c57
--- /dev/null
@@ -0,0 +1,296 @@
+// 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
+  ));
+}
diff --git a/src/Canvas/gui_mgr.hxx b/src/Canvas/gui_mgr.hxx
new file mode 100644 (file)
index 0000000..6b010a0
--- /dev/null
@@ -0,0 +1,71 @@
+// 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_ */
diff --git a/src/Canvas/placement.cxx b/src/Canvas/placement.cxx
new file mode 100644 (file)
index 0000000..c2634b6
--- /dev/null
@@ -0,0 +1,36 @@
+// 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
diff --git a/src/Canvas/placement.hxx b/src/Canvas/placement.hxx
new file mode 100644 (file)
index 0000000..e424f21
--- /dev/null
@@ -0,0 +1,38 @@
+// 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_ */
diff --git a/src/Canvas/property_based_element.cxx b/src/Canvas/property_based_element.cxx
new file mode 100644 (file)
index 0000000..3b801a7
--- /dev/null
@@ -0,0 +1,32 @@
+// 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);
+}
diff --git a/src/Canvas/property_based_element.hxx b/src/Canvas/property_based_element.hxx
new file mode 100644 (file)
index 0000000..358ae7d
--- /dev/null
@@ -0,0 +1,46 @@
+// 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_ */
diff --git a/src/Canvas/property_based_mgr.cxx b/src/Canvas/property_based_mgr.cxx
new file mode 100644 (file)
index 0000000..1d57228
--- /dev/null
@@ -0,0 +1,118 @@
+// 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()
+{
+
+}
diff --git a/src/Canvas/property_based_mgr.hxx b/src/Canvas/property_based_mgr.hxx
new file mode 100644 (file)
index 0000000..904b3c6
--- /dev/null
@@ -0,0 +1,75 @@
+// 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_ */
index 7bf65404ede70eb57be0dc8b001ace02588b3ba7..795dd72d0cc1b3d2992af6fc126872a0a56f4d00 100644 (file)
@@ -44,4 +44,16 @@ namespace canvas
     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) );
+  }
 }
index 429cc636e60c7eff782b397632fbc4e1e7b8b213..dbafdd77eb279634f49bea0bf8929ea953d04738 100644 (file)
@@ -78,6 +78,12 @@ namespace canvas
                        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_ */
diff --git a/src/Canvas/rect.hxx b/src/Canvas/rect.hxx
new file mode 100644 (file)
index 0000000..b3b42cc
--- /dev/null
@@ -0,0 +1,68 @@
+// 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_ */
diff --git a/src/Canvas/window.cxx b/src/Canvas/window.cxx
new file mode 100644 (file)
index 0000000..40dc855
--- /dev/null
@@ -0,0 +1,177 @@
+// 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
diff --git a/src/Canvas/window.hxx b/src/Canvas/window.hxx
new file mode 100644 (file)
index 0000000..4b937f3
--- /dev/null
@@ -0,0 +1,66 @@
+// 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_ */
index a721bf7659d6593652983cc6db47fae8d4c000b5..85453af7ed968e18f09818d775ed99350d0815f4 100644 (file)
@@ -66,7 +66,7 @@ using namespace std;
 
 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;
@@ -620,7 +620,6 @@ double FGPropulsion::GetTanksWeight(void) const
 
 const FGMatrix33& FGPropulsion::CalculateTankInertias(void)
 {
-  const FGMatrix33 Ts2b(-inchtoft, 0., 0., 0., inchtoft, 0., 0., 0., -inchtoft);
   unsigned int size;
 
   size = Tanks.size();
@@ -629,10 +628,10 @@ const FGMatrix33& FGPropulsion::CalculateTankInertias(void)
   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();
index 0a7fe3fb0b36892f79406fff49b43f624ac7aec0..b021d840b13c711aa42c51990ed9913ab1af7ee2 100644 (file)
@@ -2,6 +2,7 @@ include(FlightGearComponent)
 
 set(SOURCES
        AirportList.cxx
+       CanvasWidget.cxx
        MapWidget.cxx
        WaypointList.cxx
        dialog.cxx
@@ -21,6 +22,7 @@ set(SOURCES
 
 set(HEADERS
        AirportList.hxx
+       CanvasWidget.hxx
        MapWidget.hxx
        WaypointList.hxx
        dialog.hxx
diff --git a/src/GUI/CanvasWidget.cxx b/src/GUI/CanvasWidget.cxx
new file mode 100644 (file)
index 0000000..fea0f15
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * 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);
+}
diff --git a/src/GUI/CanvasWidget.hxx b/src/GUI/CanvasWidget.hxx
new file mode 100644 (file)
index 0000000..7f4552c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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_ */
index 3a9ca2c7912a8f78af726efb82f292663418b332..937eaeb78936480d186383a4fd31e387260b7c99 100644 (file)
@@ -66,10 +66,11 @@ const GuiFont guifonts[] = {
     { "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() :
index 61bba82b680095f8ecc4cb55f5ae529bfd0e9d38..9b2bc232a47087d536cede2d0fc0e58b3aeb36c8 100644 (file)
@@ -18,6 +18,7 @@
 #include "property_list.hxx"
 #include "layout.hxx"
 #include "WaypointList.hxx"
+#include "CanvasWidget.hxx"
 #include "MapWidget.hxx"
 #include "FGFontCache.hxx"
 #include "FGColor.hxx"
@@ -827,6 +828,13 @@ FGPUIDialog::makeObject (SGPropertyNode *props, int parentWidth, int parentHeigh
         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));
index 4f9485e925e51b6303ab6ae0d72153331e06c3a0..e000742540e30ce49fb84c765ed60e3f680ca5c2 100644 (file)
@@ -49,10 +49,12 @@ NewGUI::NewGUI () :
   _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 ()
index bfde62385875806c35ea7e3d2cc2bdc7cc56dbe6..36d9f0b975624cbe61f53ea45aa66d4030dc2aad 100644 (file)
@@ -85,29 +85,36 @@ ADF::init ()
 {
     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();
@@ -125,10 +132,13 @@ ADF::update (double delta_time_sec)
             || !_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") {
index c8f36e4ff5ad77085e1fb67a538aa6bf880f6b23..04355b7678e57562d0929c503d0a2add7517da9e 100644 (file)
@@ -82,6 +82,7 @@ private:
     SGPropertyNode_ptr _ident_audible_node;
     SGPropertyNode_ptr _volume_node;
     SGPropertyNode_ptr _power_btn_node;
+    SGPropertyNode_ptr _operable_node;
 
     double _time_before_search_sec;
 
index e46a37020853c7cce34276782712264d507eab32..121df9bd8b6065fecaf8dfe292b535b681b64de8 100644 (file)
@@ -200,7 +200,7 @@ bool FGInstrumentMgr::build (SGPropertyNode* config_props)
             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 ) );
@@ -215,13 +215,13 @@ bool FGInstrumentMgr::build (SGPropertyNode* config_props)
             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);
index e560652c77b2a7fe30debe48cdb10430ef8c1237..4c054ff9c604f43ea2f84c14cc37c386abb44932 100644 (file)
@@ -168,7 +168,7 @@ FGNavRadio::init ()
 {
     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);
index 6daab2ba88407eaa2db4d21929793b1f84dfa5b4..2a003706f4d963229c09a1fac88571294e2c09f9 100644 (file)
@@ -255,7 +255,7 @@ void FGODGauge::updateSampling()
 
   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(
@@ -311,7 +311,7 @@ class ReplaceStaticTextureVisitor:
      * 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;
     }
@@ -386,7 +386,9 @@ class ReplaceStaticTextureVisitor:
         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,
@@ -407,9 +409,37 @@ class ReplaceStaticTextureVisitor:
       }
     }
 
+  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
@@ -418,11 +448,12 @@ class ReplaceStaticTextureVisitor:
     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);
@@ -431,9 +462,9 @@ class ReplaceStaticTextureVisitor:
 }
 
 //------------------------------------------------------------------------------
-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);
index 902d20e6abb18bceb1bef16282509474ba534ec9..13ae907519aa88fb31200fea4e318d2c07d4fbf5 100644 (file)
@@ -29,6 +29,9 @@
 #ifndef _OD_GAUGE_HXX
 #define _OD_GAUGE_HXX
 
+#include <Canvas/canvas_fwd.hpp>
+#include <Canvas/placement.hxx>
+
 #include <osg/NodeCallback>
 #include <osg/Group>
 
@@ -38,14 +41,13 @@ namespace osg {
 }
 
 class SGPropertyNode;
-typedef std::vector<osg::ref_ptr<osg::Group> > Placements;
 
 /**
  * Owner Drawn Gauge helper class.
  */
 class FGODGauge
 {
-public:
+  public:
     FGODGauge();
     virtual ~FGODGauge();
 
@@ -109,7 +111,9 @@ public:
      * @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.
@@ -125,16 +129,17 @@ public:
      *        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.
index b1f81be656ebf2e293ba902f662e6331943a4990..c773c6c2c3014ad7d8f7a4c333dcac056364b231 100644 (file)
@@ -247,6 +247,7 @@ wxRadarBg::init ()
     camera->addChild(_textGeode.get());
 
     updateFont();
+    _time = 0.0;
 }
 
 
@@ -299,7 +300,7 @@ wxRadarBg::update (double delta_time_sec)
     if (_time < _interval)
         return;
 
-    _time = 0.0;
+    _time -= _interval;
 
     string mode = _Instrument->getStringValue("display-mode", "arc");
     if (mode == "map") {
index 9c11836aebff2b2802505bf3983ac710fb2d77a6..21711098b75ddfc52503f90e9ba68af5ecf0ea63 100644 (file)
@@ -531,6 +531,30 @@ do_tile_cache_reload (const SGPropertyNode * arg)
     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 
@@ -1531,6 +1555,7 @@ static struct {
     { "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
 };
index 85dbbd4d67551d2c35dcff4e6ecce8778a77973d..7b7f7fff961a5249b0252bbd71b7109306979594 100644 (file)
@@ -81,6 +81,7 @@
 #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>
@@ -1163,7 +1164,8 @@ bool fgInitSubsystems() {
     ////////////////////////////////////////////////////////////////////
     // 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
index 7b904d3a245f492f97246ca1a2613c766926557e..b1a39078afdb5d98df13fa9671493c7dd713ff97 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <simgear/io/HTTPClient.hxx>
 #include <simgear/io/HTTPRequest.hxx>
+#include <simgear/io/raw_socket.hxx>
 #include <simgear/timing/timestamp.hxx>
 
 using namespace std;
@@ -547,6 +548,8 @@ int main(int argc, char *argv[])
        string proxy_host, proxy_port;
        getproxy(proxy_host, proxy_port);
 
+  Socket::initSockets();
+  
     HTTP::Client http;
     http.setProxy(proxy_host, atoi(proxy_port.c_str()));
     
index 142d7af4080d95b313853bdbb3c9757330f073e6..0310274bd612c38cf55dbb38ff08a17e0dd9ac26 100644 (file)
@@ -81,7 +81,7 @@ FGModelMgr::add_model (SGPropertyNode * node)
         << t.getFormattedMessage() << t.getOrigin());
     return;
   }
-  
+
   Instance * instance = new Instance;
   SGModelPlacement *model = new SGModelPlacement;
   instance->model = model;
@@ -161,6 +161,7 @@ struct UpdateFunctor : public std::unary_function<FGModelMgr::Instance*, void>
     {
         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
index b385da728fecb3fe53f27d286ab54033bed8e528..b9dfc62aad1b724c4655234056342e42737d34b2 100644 (file)
@@ -588,16 +588,14 @@ private:
     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; }
@@ -624,80 +622,104 @@ public:
     { 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;
@@ -709,7 +731,7 @@ public:
             _aiMultiplayer->setPath(modelPath.c_str());
             aiMgr->attach(_aiMultiplayer.get());
 
-            _propertyReferenceSet->setRootNode(_aiMultiplayer->getPropertyRoot());
+            _attributeData._propertyReferenceSet->setRootNode(_aiMultiplayer->getPropertyRoot());
         }
     }
 
@@ -721,7 +743,7 @@ public:
         _aiMultiplayer = 0;
     }
 
-private:
+    MPAttributeData _attributeData;
     SGSharedPtr<FGAIMultiplayer> _aiMultiplayer;
 };
 
@@ -735,28 +757,28 @@ public:
 
     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)
@@ -796,24 +818,24 @@ public:
     }
 
 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);
index 5a9679221073de0f22c186e25b43cbe03ffab776..e05133a3eb59b59678dc0f59825bb27c87164606 100644 (file)
@@ -108,6 +108,9 @@ void FGTileMgr::reinit()
         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();
index d3eab7a70561053a915a8618049e2b59d048c3a9..44c9563b243a68b566b40caa4debc00d425210f0 100644 (file)
@@ -4,11 +4,13 @@ set(SOURCES
        NasalSys.cxx
        nasal-props.cxx
     NasalPositioned.cxx
+    NasalCanvas.cxx
        )
 
 set(HEADERS
        NasalSys.hxx
     NasalPositioned.hxx
+    NasalCanvas.hxx
        )
 
        
diff --git a/src/Scripting/NasalCanvas.cxx b/src/Scripting/NasalCanvas.cxx
new file mode 100644 (file)
index 0000000..61bc3e9
--- /dev/null
@@ -0,0 +1,264 @@
+// 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();
+}
diff --git a/src/Scripting/NasalCanvas.hxx b/src/Scripting/NasalCanvas.hxx
new file mode 100644 (file)
index 0000000..c68fc04
--- /dev/null
@@ -0,0 +1,35 @@
+// 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
+
index 8f54c14dfabffdb6968a08b9ab7b2f6f9153b3e7..d2bcd625b999e9e14a4bf976b63caeadef611e51 100644 (file)
@@ -1291,8 +1291,13 @@ static naRef f_airport_parking(naContext c, naRef me, int argc, naRef* args)
       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;
index 1c3ec31cb2265a5e8f437d3f828ba697f23abad1..a1de1e79452588230bf1838f29cd1f0e68533055 100644 (file)
@@ -27,6 +27,8 @@
 
 #include "NasalSys.hxx"
 #include "NasalPositioned.hxx"
+#include "NasalCanvas.hxx"
+
 #include <Main/globals.hxx>
 #include <Main/util.hxx>
 #include <Main/fg_props.hxx>
@@ -548,6 +550,7 @@ void FGNasalSys::init()
     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"));
@@ -816,11 +819,12 @@ naRef FGNasalSys::parse(const char* filename, const char* buf, int len)
     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
@@ -845,6 +849,17 @@ bool FGNasalSys::handleCommand(const SGPropertyNode* arg)
     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
index 5ca64f109ff18b006b9da2ffdd9cb6f0a6bd3ed0..0dad5fd530f1d7d413d4be6187c50cb257235609 100644 (file)
@@ -102,6 +102,10 @@ public:
     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,
index eee439c7b0181267c9fac32ba36b2695359b78d4..78a2428778aa67fff42d18cda3c621e5b0e784a9 100644 (file)
@@ -54,17 +54,20 @@ naRef FGNasalSys::propNodeGhost(SGPropertyNode* handle)
 // 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;
@@ -141,13 +144,13 @@ static naRef f_setAttribute(naContext c, naRef me, int argc, naRef* args)
 
 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());
 }
 
@@ -166,7 +169,7 @@ naRef makeVectorFromVec(naContext c, const T& vec)
 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:
@@ -177,10 +180,10 @@ static naRef f_getValue(naContext c, naRef me, int argc, naRef* args)
           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());
@@ -228,12 +231,12 @@ static naRef f_setValue(naContext c, naRef me, int argc, naRef* args)
         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);
@@ -269,17 +272,17 @@ static naRef f_setDoubleValue(naContext c, naRef me, int argc, naRef* args)
     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);
@@ -390,13 +393,13 @@ static naRef f_alias(naContext c, naRef me, int argc, naRef* args)
 
 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());
 }
 
index b7d930483dbd1ef7a4968915e3eeac749127148a..5b61ffaaee1bf55fd61db819e3e83fba5c363dcd 100644 (file)
@@ -577,6 +577,7 @@ FGRenderer::init( void )
 
     if (!_classicalRenderer) {
         eventHandler->setChangeStatsCameraRenderOrder( true );
+        _sky->set_minimum_sky_visibility( 0.0 ); // A black sky appears for below that
     }
 }
 
@@ -1142,7 +1143,6 @@ FGRenderer::buildDeferredFullscreenCamera( flightgear::CameraInfo* info, const F
     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);
@@ -1188,18 +1188,18 @@ FGRenderer::buildDeferredFullscreenCamera( flightgear::CameraInfo* info, osg::Gr
 }
 
 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);
@@ -1211,6 +1211,7 @@ FGRenderer::buildDeferredDisplayCamera( osg::Camera* camera, flightgear::CameraI
 
     osg::StateSet* ss = camera->getOrCreateStateSet();
     ss->addUniform( _depthInColor );
+    ss->addUniform( info->bufferSize );
 }
 
 void
@@ -1237,7 +1238,7 @@ FGRenderer::buildStage(CameraInfo* info,
         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");
 
@@ -1268,6 +1269,8 @@ FGRenderer::buildLightingLightsPass(CameraInfo* info, FGRenderingPipeline::Pass*
     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);
index 75d5c16f7dd72b1b1c1c14829a644320feb3288c..2ff7c825224d48e95ae0d719338bbf917845aef4 100644 (file)
@@ -152,7 +152,7 @@ protected:
     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;
index 5ca224d15ec78fd45c8c32c1aa7d394e6dcb97d4..fa3ce462d600e775bc16b3c2d8416cbc08346161 100644 (file)
@@ -1,6 +1,6 @@
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
-#endif 
+#endif
 
 #include <simgear/compiler.h>
 
@@ -23,8 +23,10 @@ MIDGTrack::MIDGTrack() {};
 MIDGTrack::~MIDGTrack() {};
 
 
-
-
+/*
+ * Unused function
+ */
+#if(0)
 static uint32_t read_swab( char *buf, size_t offset, size_t size ) {
     uint32_t result = 0;
 
@@ -51,6 +53,7 @@ static uint32_t read_swab( char *buf, size_t offset, size_t size ) {
 
     return result;
 }
+#endif
 
 
 static bool validate_cksum( uint8_t id, uint8_t size, char *buf,
@@ -88,6 +91,10 @@ 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;
@@ -98,7 +105,7 @@ void MIDGTrack::parse_msg( const int id, char *buf, MIDGpos *pos, MIDGatt *att )
         // 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;
@@ -312,18 +319,19 @@ void MIDGTrack::parse_msg( const int id, char *buf, MIDGpos *pos, MIDGatt *att )
         // 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
 }
 
 
@@ -463,7 +471,7 @@ int MIDGTrack::next_message( SGIOChannel *ch, SGIOChannel *log,
     // 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;
@@ -480,7 +488,6 @@ int MIDGTrack::next_message( SGSerialPort *serial, SGIOChannel *log,
 {
     char tmpbuf[256];
     char savebuf[256];
-    int result = 0;
 
     cout << "in next_message()" << endl;
 
@@ -488,7 +495,7 @@ int MIDGTrack::next_message( SGSerialPort *serial, SGIOChannel *log,
 
     // 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 ) {
@@ -514,7 +521,7 @@ int MIDGTrack::next_message( SGSerialPort *serial, SGIOChannel *log,
     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 );
 
@@ -529,7 +536,7 @@ int MIDGTrack::next_message( SGSerialPort *serial, SGIOChannel *log,
     cout << "Check sum failure!" << endl;
     return -1;
 
-    
+
 }
 
 
index 118c6198bf960c8c0c6190394bb98898a2c3d79c..72a798808b77c85e5d08f50b0ad48e369eacced4 100644 (file)
@@ -77,15 +77,15 @@ bool inited = false;
 // 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 {
@@ -94,15 +94,15 @@ static void htond (double &x)
 }
 
 // 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;
@@ -279,16 +279,13 @@ static void midg2fg( const MIDGpos pos, const MIDGatt att,
 
 
 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);
 }
 
 
@@ -466,10 +463,10 @@ int main( int argc, char **argv ) {
 
         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;
@@ -566,7 +563,6 @@ int main( int argc, char **argv ) {
         // process incoming data from the serial port
 
         int count = 0;
-        double current_time = 0.0;
 
         MIDGpos pos;
         MIDGatt att;
@@ -602,14 +598,14 @@ int main( int argc, char **argv ) {
             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;
                 }
index 2a570e1e9070a9ea8c659463fffc0053f67223d3..c81ec350d93c4b4331da6e9f02782c45beafe2d3 100644 (file)
@@ -1,6 +1,6 @@
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
-#endif 
+#endif
 
 #include <iostream>
 #include <cstdio>
@@ -430,7 +430,7 @@ int UGTrack::next_message( SGIOChannel *ch, SGIOChannel *log,
     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,
@@ -451,7 +451,6 @@ int UGTrack::next_message( SGSerialPort *serial, SGIOChannel *log,
 {
     char tmpbuf[256];
     char savebuf[256];
-    int result = 0;
 
     // cout << "in next_message()" << endl;
 
@@ -460,7 +459,7 @@ int UGTrack::next_message( SGSerialPort *serial, SGIOChannel *log,
     // 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 ) {
@@ -493,7 +492,7 @@ int UGTrack::next_message( SGSerialPort *serial, SGIOChannel *log,
     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,
@@ -505,7 +504,7 @@ int UGTrack::next_message( SGSerialPort *serial, SGIOChannel *log,
     cout << "Check sum failure!" << endl;
     return -1;
 
-    
+
 }
 
 
index 43d44b6f2af0ec05ebe94805d61dbc71d587fb3b..d2417226a7eeabe5cae12a12e7a14a627e85856b 100644 (file)
@@ -100,15 +100,15 @@ float gps_status = -1.0;
 // 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 {
@@ -117,15 +117,15 @@ static void htond (double &x)
 }
 
 // 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;
@@ -353,7 +353,7 @@ static void ugear2fg( gps *gpspacket, imu *imupacket, nav *navpacket,
     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;
@@ -499,7 +499,6 @@ static void ugear2opengc( gps *gpspacket, imu *imupacket, nav *navpacket,
 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 );
@@ -514,8 +513,8 @@ static void send_data_udp( gps *gpspacket, imu *imupacket, nav *navpacket,
              &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);
 }
 
@@ -776,16 +775,16 @@ int main( int argc, char **argv ) {
 
         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 );
 
@@ -1087,7 +1086,7 @@ int main( int argc, char **argv ) {
                 } else {
                     cout << "oops health back in time: " << healthpacket.time << " " << health_time << endl;
                 }
-                
+
             }
 
             if ( (current_time > gps_time + 2) ||
@@ -1106,7 +1105,7 @@ int main( int argc, char **argv ) {
                 command_mgr.add("hb");
                 command_heartbeat = current_time;
             }
-                
+
             // Command update @ 1hz
             if ( current_time >= command_time + 1 ) {
                 command_mgr.update(&uavcom);
@@ -1120,8 +1119,6 @@ int main( int argc, char **argv ) {
                 // 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",
index 5dfc76c6729a242fb23ba392a0b29b7c0d3d4bf3..d28f8f1f4c58b7613ed6e874c2b32e3f615a88a5 100644 (file)
@@ -60,15 +60,15 @@ bool inited = false;
 // 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 {
@@ -77,15 +77,15 @@ static void htond (double &x)
 }
 
 // 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;
@@ -281,7 +281,6 @@ static void gps2fg( const GPSPoint p, FGNetFDM *fdm, FGNetCtrls *ctrls )
 
 
 static void send_data( const GPSPoint p ) {
-    int len;
 //    int ctrlsize = sizeof( FGNetCtrls );
     int fdmsize = sizeof( FGNetFDM );
 
@@ -291,7 +290,7 @@ static void send_data( const GPSPoint p ) {
     FGNetCtrls fgctrls;
 
     gps2fg( p, &fgfdm, &fgctrls );
-    len = fdm_sock.send(&fgfdm, fdmsize, 0);
+    fdm_sock.send(&fgfdm, fdmsize, 0);
 }
 
 
@@ -431,7 +430,7 @@ int main( int argc, char **argv ) {
 
     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;
index b3bbdd6b9239fa5e23718ac9e4c18f9c577ec4f2..c362bfe73de8ec6fa19543d3f7cb20e4d72e25d3 100644 (file)
@@ -66,11 +66,12 @@ const GuiFont guifonts[] = {
     { "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()
index 5786a698724f5e8133ef21d3408c28859536d8f2..a23336dab3df08a9b9217acf79de2b572c115b21 100644 (file)
@@ -1,6 +1,6 @@
 // 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;
@@ -81,8 +82,8 @@ main(int argc, char** argv)
         // 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;
@@ -90,8 +91,8 @@ main(int argc, char** argv)
         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.");
         }
     }
 
@@ -100,10 +101,7 @@ main(int argc, char** argv)
         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);
@@ -139,23 +137,30 @@ main(int argc, char** argv)
         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);
 
@@ -170,8 +175,6 @@ main(int argc, char** argv)
     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");
 
@@ -179,8 +182,11 @@ main(int argc, char** argv)
     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 {
@@ -191,17 +197,13 @@ main(int argc, char** argv)
 
     // 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();
 }
diff --git a/version b/version
index 834f2629538327723c074ed4c3addca9888f0256..c8e38b614057b7e417c63fde44726a4143de9da0 100644 (file)
--- a/version
+++ b/version
@@ -1 +1 @@
-2.8.0
+2.9.0