diff --git a/projects/VC90/FlightGear.sln b/projects/VC90/FlightGear.sln index bb1d39b4b..90ea51407 100644 --- a/projects/VC90/FlightGear.sln +++ b/projects/VC90/FlightGear.sln @@ -54,6 +54,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yasim", "yasim\yasim.vcproj EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimGear", "..\..\..\Simgear\projects\VC90\SimGear.vcproj", "{22540CD3-D3CA-4C86-A773-80AEEE3ACDED}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fgpanel", "fgpanel\fgpanel.vcproj", "{FA27B353-179C-4DE8-B3AC-E260F8F790DD}" + ProjectSection(ProjectDependencies) = postProject + {22540CD3-D3CA-4C86-A773-80AEEE3ACDED} = {22540CD3-D3CA-4C86-A773-80AEEE3ACDED} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -156,6 +161,12 @@ Global {22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Release|Win32.Build.0 = Release|Win32 {22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Release|x64.ActiveCfg = Release|x64 {22540CD3-D3CA-4C86-A773-80AEEE3ACDED}.Release|x64.Build.0 = Release|x64 + {FA27B353-179C-4DE8-B3AC-E260F8F790DD}.Debug|Win32.ActiveCfg = Debug|Win32 + {FA27B353-179C-4DE8-B3AC-E260F8F790DD}.Debug|Win32.Build.0 = Debug|Win32 + {FA27B353-179C-4DE8-B3AC-E260F8F790DD}.Debug|x64.ActiveCfg = Debug|Win32 + {FA27B353-179C-4DE8-B3AC-E260F8F790DD}.Release|Win32.ActiveCfg = Release|Win32 + {FA27B353-179C-4DE8-B3AC-E260F8F790DD}.Release|Win32.Build.0 = Release|Win32 + {FA27B353-179C-4DE8-B3AC-E260F8F790DD}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/projects/VC90/FlightGear/FlightGear.vcproj b/projects/VC90/FlightGear/FlightGear.vcproj index f7d56ff93..8d70c4028 100644 --- a/projects/VC90/FlightGear/FlightGear.vcproj +++ b/projects/VC90/FlightGear/FlightGear.vcproj @@ -3033,14 +3033,6 @@ RelativePath="..\..\..\src\Network\jsclient.hxx" > </File> - <File - RelativePath="..\..\..\src\Network\multiplay.cxx" - > - </File> - <File - RelativePath="..\..\..\src\Network\multiplay.hxx" - > - </File> <File RelativePath="..\..\..\src\Network\native.cxx" > diff --git a/projects/VC90/fgpanel/fgpanel.vcproj b/projects/VC90/fgpanel/fgpanel.vcproj index 47b67eb33..bc09aff71 100755 --- a/projects/VC90/fgpanel/fgpanel.vcproj +++ b/projects/VC90/fgpanel/fgpanel.vcproj @@ -18,10 +18,10 @@ <Configurations> <Configuration Name="Debug|Win32" - OutputDirectory="$(SolutionDir)$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)" + OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" ConfigurationType="1" - CharacterSet="1" + CharacterSet="2" > <Tool Name="VCPreBuildEventTool" @@ -41,7 +41,8 @@ <Tool Name="VCCLCompilerTool" Optimization="0" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" + AdditionalIncludeDirectories="..\..\..\..\SimGear;..\..\..\..\boost_1_44_0;..\..\..\..\install\msvc90\OpenSceneGraph\include;..\..\..\..\3rdParty\include;..\..\..\src\include" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;NOMINMAX;HAVE_CONFIG_H" MinimalRebuild="true" BasicRuntimeChecks="3" RuntimeLibrary="3" @@ -60,7 +61,9 @@ /> <Tool Name="VCLinkerTool" + AdditionalDependencies="wsock32.lib zlibd.lib libpngd.lib fnt_d.lib ul_d.lib sg_d.lib pui_d.lib" LinkIncremental="2" + AdditionalLibraryDirectories="..\..\..\..\install\msvc90\OpenSceneGraph\lib;..\..\..\..\3rdParty\lib" GenerateDebugInformation="true" SubSystem="1" TargetMachine="1" @@ -89,8 +92,8 @@ </Configuration> <Configuration Name="Release|Win32" - OutputDirectory="$(SolutionDir)$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)" + OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)" + IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" ConfigurationType="1" CharacterSet="2" WholeProgramOptimization="1" diff --git a/src/Environment/environment_mgr.cxx b/src/Environment/environment_mgr.cxx index e48039029..42023ea84 100644 --- a/src/Environment/environment_mgr.cxx +++ b/src/Environment/environment_mgr.cxx @@ -97,6 +97,13 @@ FGEnvironmentMgr::init () SG_LOG( SG_GENERAL, SG_INFO, "Initializing environment subsystem"); SGSubsystemGroup::init(); fgClouds->Init(); + + // Initialize the longitude, latitude and altitude to the initial position + // of the aircraft so that the atmospheric properties (pressure, temperature + // and density) can be initialized accordingly. + _altitudeNode->setDoubleValue(fgGetDouble("/sim/presets/altitude-ft")); + _longitude_n->setDoubleValue(fgGetDouble("/sim/presets/longitude-deg")); + _latitude_n->setDoubleValue(fgGetDouble("/sim/presets/latitude-deg")); } void diff --git a/src/FDM/JSBSim/JSBSim.cxx b/src/FDM/JSBSim/JSBSim.cxx index 806401cf9..54ed59872 100644 --- a/src/FDM/JSBSim/JSBSim.cxx +++ b/src/FDM/JSBSim/JSBSim.cxx @@ -181,7 +181,7 @@ FGJSBsim::FGJSBsim( double dt ) MassBalance = fdmex->GetMassBalance(); Propulsion = fdmex->GetPropulsion(); Aircraft = fdmex->GetAircraft(); - Propagate = fdmex->GetPropagate(); + Propagate = fdmex->GetPropagate(); Auxiliary = fdmex->GetAuxiliary(); Inertial = fdmex->GetInertial(); Aerodynamics = fdmex->GetAerodynamics(); @@ -369,9 +369,9 @@ void FGJSBsim::init() Atmosphere->UseInternal(); } - fgic->SetVNorthFpsIC( -wind_from_north->getDoubleValue() ); - fgic->SetVEastFpsIC( -wind_from_east->getDoubleValue() ); - fgic->SetVDownFpsIC( -wind_from_down->getDoubleValue() ); + fgic->SetWindNEDFpsIC( -wind_from_north->getDoubleValue(), + -wind_from_east->getDoubleValue(), + -wind_from_down->getDoubleValue() ); //Atmosphere->SetExTemperature(get_Static_temperature()); //Atmosphere->SetExPressure(get_Static_pressure()); @@ -393,20 +393,20 @@ void FGJSBsim::init() } // end of egt_degf deprecation patch - if (fgGetBool("/sim/presets/running")) { - for (unsigned int i=0; i < Propulsion->GetNumEngines(); i++) { - SGPropertyNode * node = fgGetNode("engines/engine", i, true); - node->setBoolValue("running", true); - Propulsion->GetEngine(i)->SetRunning(true); - } - } - FCS->SetDfPos( ofNorm, globals->get_controls()->get_flaps() ); common_init(); copy_to_JSBsim(); fdmex->RunIC(); //loop JSBSim once w/o integrating + if (fgGetBool("/sim/presets/running")) { + Propulsion->InitRunning(-1); + for (unsigned int i = 0; i < Propulsion->GetNumEngines(); i++) { + FGPiston* eng = (FGPiston*)Propulsion->GetEngine(i); + globals->get_controls()->set_magnetos(i, eng->GetMagnetos()); + globals->get_controls()->set_mixture(i, FCS->GetMixtureCmd(i)); + } + } copy_from_JSBsim(); //update the bus SG_LOG( SG_FLIGHT, SG_INFO, " Initialized JSBSim with:" ); @@ -1282,7 +1282,7 @@ void FGJSBsim::do_trim(void) { fgtrim = new FGTrim(fdmex,tGround); } else { - fgtrim = new FGTrim(fdmex,tLongitudinal); + fgtrim = new FGTrim(fdmex,tFull); } if ( !fgtrim->DoTrim() ) { @@ -1296,7 +1296,7 @@ void FGJSBsim::do_trim(void) pitch_trim->setDoubleValue( FCS->GetPitchTrimCmd() ); throttle_trim->setDoubleValue( FCS->GetThrottleCmd(0) ); aileron_trim->setDoubleValue( FCS->GetDaCmd() ); - rudder_trim->setDoubleValue( FCS->GetDrCmd() ); + rudder_trim->setDoubleValue( -FCS->GetDrCmd() ); globals->get_controls()->set_elevator_trim(FCS->GetPitchTrimCmd()); globals->get_controls()->set_elevator(FCS->GetDeCmd()); @@ -1304,7 +1304,7 @@ void FGJSBsim::do_trim(void) globals->get_controls()->set_throttle(i, FCS->GetThrottleCmd(i)); globals->get_controls()->set_aileron(FCS->GetDaCmd()); - globals->get_controls()->set_rudder( FCS->GetDrCmd()); + globals->get_controls()->set_rudder( -FCS->GetDrCmd()); SG_LOG( SG_FLIGHT, SG_INFO, " Trim complete" ); } diff --git a/src/FDM/JSBSim/initialization/FGInitialCondition.cpp b/src/FDM/JSBSim/initialization/FGInitialCondition.cpp index 0dbcf88ce..00a3840f1 100644 --- a/src/FDM/JSBSim/initialization/FGInitialCondition.cpp +++ b/src/FDM/JSBSim/initialization/FGInitialCondition.cpp @@ -61,7 +61,7 @@ using namespace std; namespace JSBSim { -static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.59 2011/04/03 13:18:51 bcoconni Exp $"; +static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.61 2011/05/20 00:47:03 bcoconni Exp $"; static const char *IdHdr = ID_INITIALCONDITION; //****************************************************************************** @@ -112,7 +112,7 @@ void FGInitialCondition::ResetIC(double u0, double v0, double w0, FGQuaternion Quat(phi, theta, psi); Quat.Normalize(); Tl2b = Quat.GetT(); - Tb2l = Quat.GetTInv(); + Tb2l = Tl2b.Transposed(); vUVW_NED = Tb2l * FGColumnVector3(u0, v0, w0); vt = vUVW_NED.Magnitude(); @@ -322,20 +322,18 @@ void FGInitialCondition::SetClimbRateFpsIC(double hdot) FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.); FGColumnVector3 _WIND_NED = _vt_NED - vUVW_NED; - double hdot0 = _vt_NED(eW); + double hdot0 = -_vt_NED(eW); if (fabs(hdot0) < vt) { double scale = sqrt((vt*vt-hdot*hdot)/(vt*vt-hdot0*hdot0)); _vt_NED(eU) *= scale; _vt_NED(eV) *= scale; } - _vt_NED(eW) = hdot; + _vt_NED(eW) = -hdot; vUVW_NED = _vt_NED - _WIND_NED; - // The AoA is not modified here but the function SetAlphaRadIC is updating the - // same angles than SetClimbRateFpsIC needs to update. - // TODO : create a subroutine that only shares the relevant code. - SetAlphaRadIC(alpha); + // Updating the angles theta and beta to keep the true airspeed amplitude + calcThetaBeta(alpha, _vt_NED); } //****************************************************************************** @@ -346,13 +344,22 @@ void FGInitialCondition::SetClimbRateFpsIC(double hdot) void FGInitialCondition::SetAlphaRadIC(double alfa) { FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.); + calcThetaBeta(alfa, _vt_NED); +} +//****************************************************************************** +// When the AoA is modified, we need to update the angles theta and beta to +// keep the true airspeed amplitude, the climb rate and the heading unchanged. +// Beta will be modified if the aircraft roll angle is not null. + +void FGInitialCondition::calcThetaBeta(double alfa, const FGColumnVector3& _vt_NED) +{ double calpha = cos(alfa), salpha = sin(alfa); double cpsi = cos(psi), spsi = sin(psi); double cphi = cos(phi), sphi = sin(phi); FGMatrix33 Tpsi( cpsi, spsi, 0., - -spsi, cpsi, 0., - 0., 0., 1.); + -spsi, cpsi, 0., + 0., 0., 1.); FGMatrix33 Tphi(1., 0., 0., 0., cphi, sphi, 0.,-sphi, cphi); @@ -398,11 +405,11 @@ void FGInitialCondition::SetAlphaRadIC(double alfa) Tl2b = Quat.GetT(); Tb2l = Quat.GetTInv(); - FGColumnVector3 v2 = Talpha * Quat.GetT() * _vt_NED; + FGColumnVector3 v2 = Talpha * Tl2b * _vt_NED; alpha = alfa; beta = atan2(v2(eV), v2(eU)); - double cbeta=0.0, sbeta=0.0; + double cbeta=1.0, sbeta=0.0; if (vt != 0.0) { cbeta = v2(eU) / vt; sbeta = v2(eV) / vt; @@ -687,6 +694,8 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt) double ve0 = vt * sqrt(rho/rhoSL); altitudeASL=alt; + position.SetRadius(alt + sea_level_radius); + temperature = fdmex->GetAtmosphere()->GetTemperature(altitudeASL); soundSpeed = sqrt(SHRatio*Reng*temperature); rho = fdmex->GetAtmosphere()->GetDensity(altitudeASL); @@ -703,8 +712,6 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt) default: // Make the compiler stop complaining about missing enums break; } - - position.SetRadius(alt + sea_level_radius); } //****************************************************************************** diff --git a/src/FDM/JSBSim/initialization/FGInitialCondition.h b/src/FDM/JSBSim/initialization/FGInitialCondition.h index 308122450..e110ebbb3 100644 --- a/src/FDM/JSBSim/initialization/FGInitialCondition.h +++ b/src/FDM/JSBSim/initialization/FGInitialCondition.h @@ -54,7 +54,7 @@ INCLUDES DEFINITIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ -#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.26 2011/01/16 16:10:59 bcoconni Exp $" +#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.27 2011/05/20 00:47:03 bcoconni Exp $" /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% FORWARD DECLARATIONS @@ -213,7 +213,7 @@ CLASS DOCUMENTATION @property ic/r-rad_sec (read/write) Yaw rate initial condition in radians/second @author Tony Peden - @version "$Id: FGInitialCondition.h,v 1.26 2011/01/16 16:10:59 bcoconni Exp $" + @version "$Id: FGInitialCondition.h,v 1.27 2011/05/20 00:47:03 bcoconni Exp $" */ /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -666,6 +666,7 @@ private: double getMachFromVcas(double vcas); double calcVcas(double Mach) const; void calcAeroAngles(const FGColumnVector3& _vt_BODY); + void calcThetaBeta(double alfa, const FGColumnVector3& _vt_NED); void bind(void); void Debug(int from); diff --git a/src/FDM/flight.cxx b/src/FDM/flight.cxx index d501d1507..431605a9f 100644 --- a/src/FDM/flight.cxx +++ b/src/FDM/flight.cxx @@ -179,6 +179,15 @@ FGInterface::common_init () double slr = SGGeodesy::SGGeodToSeaLevelRadius(geodetic_position_v); _set_Sea_level_radius( slr * SG_METER_TO_FEET ); + // Set initial Euler angles + SG_LOG( SG_FLIGHT, SG_INFO, "...initializing Euler angles..." ); + set_Euler_Angles( fgGetDouble("/sim/presets/roll-deg") + * SGD_DEGREES_TO_RADIANS, + fgGetDouble("/sim/presets/pitch-deg") + * SGD_DEGREES_TO_RADIANS, + fgGetDouble("/sim/presets/heading-deg") + * SGD_DEGREES_TO_RADIANS ); + // Set initial velocities SG_LOG( SG_FLIGHT, SG_INFO, "...initializing velocities..." ); if ( !fgHasNode("/sim/presets/speed-set") ) { @@ -207,14 +216,11 @@ FGInterface::common_init () } } - // Set initial Euler angles - SG_LOG( SG_FLIGHT, SG_INFO, "...initializing Euler angles..." ); - set_Euler_Angles( fgGetDouble("/sim/presets/roll-deg") - * SGD_DEGREES_TO_RADIANS, - fgGetDouble("/sim/presets/pitch-deg") - * SGD_DEGREES_TO_RADIANS, - fgGetDouble("/sim/presets/heading-deg") - * SGD_DEGREES_TO_RADIANS ); + if ( fgHasNode("/sim/presets/glideslope-deg") ) + set_Gamma_vert_rad( fgGetDouble("/sim/presets/glideslope-deg") + * SGD_DEGREES_TO_RADIANS ); + else if ( fgHasNode( "/velocities/vertical-speed-fps") ) + set_Climb_Rate( fgGetDouble("/velocities/vertical-speed-fps") ); SG_LOG( SG_FLIGHT, SG_INFO, "End common FDM init" ); } @@ -251,7 +257,7 @@ FGInterface::bind () false); fgSetArchivable("/position/altitude-ft"); fgTie("/position/altitude-agl-ft", this, - &FGInterface::get_Altitude_AGL, &FGInterface::set_AltitudeAGL); + &FGInterface::get_Altitude_AGL, &FGInterface::set_AltitudeAGL, false); fgSetArchivable("/position/ground-elev-ft"); fgTie("/position/ground-elev-ft", this, &FGInterface::get_Runway_altitude); // read-only @@ -263,7 +269,7 @@ FGInterface::bind () fgSetArchivable("/position/sea-level-radius-ft"); fgTie("/position/sea-level-radius-ft", this, &FGInterface::get_Sea_level_radius, - &FGInterface::_set_Sea_level_radius); + &FGInterface::_set_Sea_level_radius, false); // Orientation fgTie("/orientation/roll-deg", this, @@ -279,24 +285,27 @@ FGInterface::bind () &FGInterface::set_Psi_deg, false); fgSetArchivable("/orientation/heading-deg"); fgTie("/orientation/track-deg", this, - &FGInterface::get_Track); + &FGInterface::get_Track); // read-only // Body-axis "euler rates" (rotation speed, but in a funny // representation). fgTie("/orientation/roll-rate-degps", this, - &FGInterface::get_Phi_dot_degps, &FGInterface::set_Phi_dot_degps); + &FGInterface::get_Phi_dot_degps, + &FGInterface::set_Phi_dot_degps, false); fgTie("/orientation/pitch-rate-degps", this, - &FGInterface::get_Theta_dot_degps, &FGInterface::set_Theta_dot_degps); + &FGInterface::get_Theta_dot_degps, + &FGInterface::set_Theta_dot_degps, false); fgTie("/orientation/yaw-rate-degps", this, - &FGInterface::get_Psi_dot_degps, &FGInterface::set_Psi_dot_degps); + &FGInterface::get_Psi_dot_degps, + &FGInterface::set_Psi_dot_degps, false); - fgTie("/orientation/p-body", this, &FGInterface::get_P_body); - fgTie("/orientation/q-body", this, &FGInterface::get_Q_body); - fgTie("/orientation/r-body", this, &FGInterface::get_R_body); + fgTie("/orientation/p-body", this, &FGInterface::get_P_body); // read-only + fgTie("/orientation/q-body", this, &FGInterface::get_Q_body); // read-only + fgTie("/orientation/r-body", this, &FGInterface::get_R_body); // read-only // Ground speed knots fgTie("/velocities/groundspeed-kt", this, - &FGInterface::get_V_ground_speed_kt); + &FGInterface::get_V_ground_speed_kt); // read-only // Calibrated airspeed fgTie("/velocities/airspeed-kt", this, @@ -305,7 +314,7 @@ FGInterface::bind () false); fgTie("/velocities/equivalent-kt", this, - &FGInterface::get_V_equiv_kts); + &FGInterface::get_V_equiv_kts); // read-only // Mach number fgTie("/velocities/mach", this, @@ -338,11 +347,11 @@ FGInterface::bind () &FGInterface::get_V_down, &FGInterface::set_V_down, false); fgTie("/velocities/north-relground-fps", this, - &FGInterface::get_V_north_rel_ground); + &FGInterface::get_V_north_rel_ground); // read-only fgTie("/velocities/east-relground-fps", this, - &FGInterface::get_V_east_rel_ground); + &FGInterface::get_V_east_rel_ground); // read-only fgTie("/velocities/down-relground-fps", this, - &FGInterface::get_V_down_rel_ground); + &FGInterface::get_V_down_rel_ground); // read-only // Relative wind @@ -367,36 +376,37 @@ FGInterface::bind () // Climb and slip (read-only) fgTie("/velocities/vertical-speed-fps", this, &FGInterface::get_Climb_Rate, - &FGInterface::set_Climb_Rate ); + &FGInterface::set_Climb_Rate, false ); fgTie("/velocities/glideslope", this, &FGInterface::get_Gamma_vert_rad, - &FGInterface::set_Gamma_vert_rad ); + &FGInterface::set_Gamma_vert_rad, false ); fgTie("/orientation/side-slip-rad", this, - &FGInterface::get_Beta, &FGInterface::_set_Beta); + &FGInterface::get_Beta, &FGInterface::_set_Beta, false); fgTie("/orientation/side-slip-deg", this, &FGInterface::get_Beta_deg); // read-only fgTie("/orientation/alpha-deg", this, - &FGInterface::get_Alpha_deg, &FGInterface::set_Alpha_deg); // read-only + &FGInterface::get_Alpha_deg, &FGInterface::set_Alpha_deg, false); fgTie("/accelerations/nlf", this, &FGInterface::get_Nlf); // read-only // NED accelerations fgTie("/accelerations/ned/north-accel-fps_sec", - this, &FGInterface::get_V_dot_north); + this, &FGInterface::get_V_dot_north); // read-only fgTie("/accelerations/ned/east-accel-fps_sec", - this, &FGInterface::get_V_dot_east); + this, &FGInterface::get_V_dot_east); // read-only fgTie("/accelerations/ned/down-accel-fps_sec", - this, &FGInterface::get_V_dot_down); + this, &FGInterface::get_V_dot_down); // read-only // Pilot accelerations fgTie("/accelerations/pilot/x-accel-fps_sec", - this, &FGInterface::get_A_X_pilot, &FGInterface::set_A_X_pilot); + this, &FGInterface::get_A_X_pilot, &FGInterface::set_A_X_pilot, false); fgTie("/accelerations/pilot/y-accel-fps_sec", - this, &FGInterface::get_A_Y_pilot, &FGInterface::set_A_Y_pilot); + this, &FGInterface::get_A_Y_pilot, &FGInterface::set_A_Y_pilot, false); fgTie("/accelerations/pilot/z-accel-fps_sec", - this, &FGInterface::get_A_Z_pilot, &FGInterface::set_A_Z_pilot); + this, &FGInterface::get_A_Z_pilot, &FGInterface::set_A_Z_pilot, false); - fgTie("/accelerations/n-z-cg-fps_sec", this, &FGInterface::get_N_Z_cg); + fgTie("/accelerations/n-z-cg-fps_sec", + this, &FGInterface::get_N_Z_cg); // read-only } diff --git a/src/GUI/gui_funcs.cxx b/src/GUI/gui_funcs.cxx index ccbd0a550..06459a8f6 100644 --- a/src/GUI/gui_funcs.cxx +++ b/src/GUI/gui_funcs.cxx @@ -42,6 +42,7 @@ #include <simgear/debug/logstream.hxx> #include <simgear/misc/sg_path.hxx> #include <simgear/screen/screen-dump.hxx> +#include <simgear/structure/event_mgr.hxx> #include <Cockpit/panel.hxx> #include <Main/globals.hxx> @@ -49,8 +50,11 @@ #include <Main/fg_os.hxx> #include <Main/renderer.hxx> #include <Main/viewmgr.hxx> +#include <Main/WindowSystemAdapter.hxx> +#include <Main/CameraGroup.hxx> #include <GUI/new_gui.hxx> + #ifdef _WIN32 # include <shellapi.h> #endif @@ -406,9 +410,134 @@ void fgHiResDumpWrapper () { fgHiResDump(); } +namespace +{ + using namespace flightgear; + + class GUISnapShotOperation : + public GraphicsContextOperation + { + public: + + // start new snap shot + static bool start() + { + // allow only one snapshot at a time + if (_snapShotOp.valid()) + return false; + _snapShotOp = new GUISnapShotOperation(); + /* register with graphics context so actual snap shot is done + * in the graphics context (thread) */ + osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault()); + WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA(); + osg::GraphicsContext* gc = 0; + if (guiCamera) + gc = guiCamera->getGraphicsContext(); + if (gc) { + gc->add(_snapShotOp.get()); + } else { + wsa->windows[0]->gc->add(_snapShotOp.get()); + } + return true; + } + + private: + // constructor to be executed in main loop's thread + GUISnapShotOperation() : + flightgear::GraphicsContextOperation(std::string("GUI snap shot")), + _master_freeze(fgGetNode("/sim/freeze/master", true)), + _freeze(_master_freeze->getBoolValue()), + _result(false), + _mouse(fgGetMouseCursor()) + { + if (!_freeze) + _master_freeze->setBoolValue(true); + + fgSetMouseCursor(MOUSE_CURSOR_NONE); + + string dir = fgGetString("/sim/paths/screenshot-dir"); + if (dir.empty()) + dir = fgGetString("/sim/fg-current"); + + _path.set(dir + '/'); + if (_path.create_dir( 0755 )) { + SG_LOG(SG_GENERAL, SG_ALERT, "Cannot create screenshot directory '" + << dir << "'. Trying home directory."); + dir = fgGetString("/sim/fg-home"); + } + + char filename[24]; + static int count = 1; + while (count < 1000) { + snprintf(filename, 24, "fgfs-screen-%03d.png", count++); + + SGPath p(dir); + p.append(filename); + if (!p.exists()) { + _path.set(p.str()); + break; + } + } + + _xsize = fgGetInt("/sim/startup/xsize"); + _ysize = fgGetInt("/sim/startup/ysize"); + + FGRenderer *renderer = globals->get_renderer(); + renderer->resize(_xsize, _ysize); + globals->get_event_mgr()->addTask("SnapShotTimer", + this, &GUISnapShotOperation::timerExpired, + 0.1, false); + } + + // to be executed in graphics context (maybe separate thread) + void run(osg::GraphicsContext* gc) + { + _result = sg_glDumpWindow(_path.c_str(), + _xsize, + _ysize); + } + + // timer method, to be executed in main loop's thread + virtual void timerExpired() + { + if (isFinished()) + { + globals->get_event_mgr()->removeTask("SnapShotTimer"); + + fgSetString("/sim/paths/screenshot-last", _path.c_str()); + fgSetBool("/sim/signals/screenshot", _result); + + fgSetMouseCursor(_mouse); + + if ( !_freeze ) + _master_freeze->setBoolValue(false); + + _snapShotOp = 0; + } + } + + static osg::ref_ptr<GUISnapShotOperation> _snapShotOp; + SGPropertyNode_ptr _master_freeze; + bool _freeze; + bool _result; + int _mouse; + int _xsize, _ysize; + SGPath _path; + }; + +} + +osg::ref_ptr<GUISnapShotOperation> GUISnapShotOperation::_snapShotOp; // do a screen snap shot -bool fgDumpSnapShot () { +bool fgDumpSnapShot () +{ +#if 1 + // start snap shot operation, while needs to be executed in + // graphics context + return GUISnapShotOperation::start(); +#else + // obsolete code => remove when new code is stable static SGConstPropertyNode_ptr master_freeze = fgGetNode("/sim/freeze/master"); bool freeze = master_freeze->getBoolValue(); @@ -455,7 +584,7 @@ bool fgDumpSnapShot () { } } - int result = sg_glDumpWindow(path.c_str(), + bool result = sg_glDumpWindow(path.c_str(), fgGetInt("/sim/startup/xsize"), fgGetInt("/sim/startup/ysize")); @@ -467,7 +596,8 @@ bool fgDumpSnapShot () { if ( !freeze ) { fgSetBool("/sim/freeze/master", false); } - return result != 0; + return result; +#endif } // do an entire scenegraph dump diff --git a/src/Input/FGJoystickInput.cxx b/src/Input/FGJoystickInput.cxx index afc7ad8fd..506de36bb 100644 --- a/src/Input/FGJoystickInput.cxx +++ b/src/Input/FGJoystickInput.cxx @@ -49,7 +49,8 @@ FGJoystickInput::joystick::joystick () naxes(0), nbuttons(0), axes(0), - buttons(0) + buttons(0), + predefined(true) { } @@ -73,15 +74,18 @@ FGJoystickInput::FGJoystickInput() FGJoystickInput::~FGJoystickInput() { - _remove(); + _remove(true); } -void FGJoystickInput::_remove() +void FGJoystickInput::_remove(bool all) { SGPropertyNode * js_nodes = fgGetNode("/input/joysticks", true); - js_nodes->removeChildren("js", false); + for (int i = 0; i < MAX_JOYSTICKS; i++) { + // do not remove predefined joysticks info on reinit + if ((all)||(!bindings[i].predefined)) + js_nodes->removeChild("js", i, false); if (bindings[i].js) delete bindings[i].js; bindings[i].js = NULL; @@ -92,7 +96,7 @@ void FGJoystickInput::init() { jsInit(); SG_LOG(SG_INPUT, SG_DEBUG, "Initializing joystick bindings"); - SGPropertyNode * js_nodes = fgGetNode("/input/joysticks", true); + SGPropertyNode_ptr js_nodes = fgGetNode("/input/joysticks", true); FGDeviceConfigurationMap configMap("Input/Joysticks", js_nodes, "js-named"); @@ -112,6 +116,7 @@ void FGJoystickInput::init() SG_LOG(SG_INPUT, SG_INFO, "Using existing bindings for joystick " << i); } else { + bindings[i].predefined = false; SG_LOG(SG_INPUT, SG_INFO, "Looking for bindings for joystick \"" << name << '"'); SGPropertyNode_ptr named; @@ -137,7 +142,7 @@ void FGJoystickInput::init() void FGJoystickInput::reinit() { SG_LOG(SG_INPUT, SG_DEBUG, "Re-Initializing joystick bindings"); - _remove(); + _remove(false); FGJoystickInput::init(); FGJoystickInput::postinit(); } diff --git a/src/Input/FGJoystickInput.hxx b/src/Input/FGJoystickInput.hxx index 392fc54b3..45de33f94 100644 --- a/src/Input/FGJoystickInput.hxx +++ b/src/Input/FGJoystickInput.hxx @@ -25,7 +25,7 @@ #ifndef _FGJOYSTICKINPUT_HXX #define _FGJOYSTICKINPUT_HXX -#ifndef __cplusplus +#ifndef __cplusplus # error This library requires C++ #endif @@ -52,7 +52,7 @@ public: static const int MAX_JOYSTICK_BUTTONS = 32; private: - void _remove(); + void _remove(bool all); /** * Settings for a single joystick axis. @@ -83,6 +83,7 @@ private: int nbuttons; axis * axes; FGButton * buttons; + bool predefined; }; joystick bindings[MAX_JOYSTICKS]; diff --git a/src/Main/WindowBuilder.cxx b/src/Main/WindowBuilder.cxx index 740671cd5..52f09011d 100644 --- a/src/Main/WindowBuilder.cxx +++ b/src/Main/WindowBuilder.cxx @@ -69,9 +69,9 @@ WindowBuilder::makeDefaultTraits(bool stencil) traits->red = traits->green = traits->blue = cbits; traits->depth = zbits; if (alpha) - traits->alpha = 8; + traits->alpha = 8; if (stencil) - traits->stencil = 8; + traits->stencil = 8; traits->doubleBuffer = true; traits->mipMapGeneration = true; traits->windowName = "FlightGear"; @@ -83,20 +83,21 @@ WindowBuilder::makeDefaultTraits(bool stencil) unsigned width = 0; unsigned height = 0; wsi->getScreenResolution(*traits, width, height); - traits->windowDecoration = false; + traits->windowDecoration = false; traits->width = width; traits->height = height; traits->supportsResize = false; } else { - traits->windowDecoration = true; + traits->windowDecoration = true; traits->width = w; traits->height = h; -#if defined(WIN32) || defined(__APPLE__) + unsigned screenwidth = 0; + unsigned screenheight = 0; + wsi->getScreenResolution(*traits, screenwidth, screenheight); // Ugly Hack, why does CW_USEDEFAULT works like phase of the moon? // Mac also needs this to show window frame, menubar and Docks - traits->x = 100; - traits->y = 100; -#endif + traits->x = (w>screenwidth) ? 0 : (screenwidth-w)/3; + traits->y = (h>screenheight) ? 0 : (screenheight-h)/3; traits->supportsResize = true; } return traits; diff --git a/src/Main/fg_io.cxx b/src/Main/fg_io.cxx index 6d6be65f5..c45b98f86 100644 --- a/src/Main/fg_io.cxx +++ b/src/Main/fg_io.cxx @@ -65,7 +65,7 @@ #include <Network/ray.hxx> #include <Network/rul.hxx> #include <Network/generic.hxx> -#include <Network/multiplay.hxx> + #ifdef FG_HAVE_HLA #include <Network/HLA/hla.hxx> #endif @@ -219,10 +219,23 @@ FGIO::parse_port_config( const string& config ) return NULL; } string dir = tokens[1]; - string rate = tokens[2]; + int rate = atoi(tokens[2].c_str()); string host = tokens[3]; - string port = tokens[4]; - return new FGMultiplay(dir, atoi(rate.c_str()), host, atoi(port.c_str())); + + short port = atoi(tokens[4].c_str()); + + // multiplay used to be handled by an FGProtocol, but no longer. This code + // retains compatability with existing command-line syntax + fgSetInt("/sim/multiplay/tx-rate-hz", rate); + if (dir == "in") { + fgSetInt("/sim/multiplay/rxport", port); + fgSetString("/sim/multiplay/rxhost", host.c_str()); + } else if (dir == "out") { + fgSetInt("/sim/multiplay/txport", port); + fgSetString("/sim/multiplay/txhost", host.c_str()); + } + + return NULL; #ifdef FG_HAVE_HLA } else if ( protocol == "hla" ) { return new FGHLA(tokens); @@ -343,20 +356,20 @@ FGIO::init() // appropriate FGIOChannel structures string_list::iterator i = globals->get_channel_options_list()->begin(); string_list::iterator end = globals->get_channel_options_list()->end(); - for (; i != end; ++i ) - { - p = parse_port_config( *i ); - if ( p != NULL ) { - p->open(); - io_channels.push_back( p ); - if ( !p->is_enabled() ) { - SG_LOG( SG_IO, SG_ALERT, "I/O Channel config failed." ); - exit(-1); - } - } else { - SG_LOG( SG_IO, SG_INFO, "I/O Channel parse failed." ); - } - } + for (; i != end; ++i ) { + p = parse_port_config( *i ); + if (!p) { + continue; + } + + p->open(); + if ( !p->is_enabled() ) { + SG_LOG( SG_IO, SG_ALERT, "I/O Channel config failed." ); + delete p; + } + + io_channels.push_back( p ); + } // of channel options iteration } void diff --git a/src/Main/options.cxx b/src/Main/options.cxx index df50b344c..01f1e4438 100644 --- a/src/Main/options.cxx +++ b/src/Main/options.cxx @@ -1838,7 +1838,7 @@ fgUsage (bool verbose) while ( t_str.size() > 47 ) { - unsigned int m = t_str.rfind(' ', 47); + string::size_type m = t_str.rfind(' ', 47); msg += t_str.substr(0, m) + '\n'; msg.append( 32, ' '); diff --git a/src/Main/renderer.cxx b/src/Main/renderer.cxx index 4edaf2406..4902abea0 100644 --- a/src/Main/renderer.cxx +++ b/src/Main/renderer.cxx @@ -784,9 +784,14 @@ FGRenderer::resize( int width, int height ) { int curWidth = _xsize->getIntValue(), curHeight = _ysize->getIntValue(); - - _xsize->setIntValue(width); - _ysize->setIntValue(height); + if ((curHeight != height) || (curWidth != width)) { + // must guard setting these, or PLIB-PUI fails with too many live interfaces + _xsize->setIntValue(width); + _ysize->setIntValue(height); + } + + // must set view aspect ratio each frame, or initial values are wrong. + // should probably be fixed 'smarter' during view setup. double aspect = height / (double) width; // for all views diff --git a/src/Main/viewmgr.cxx b/src/Main/viewmgr.cxx index 955529189..ea9fcd7a6 100644 --- a/src/Main/viewmgr.cxx +++ b/src/Main/viewmgr.cxx @@ -356,7 +356,7 @@ FGViewMgr::update (double dt) abs_viewer_position = loop_view->getViewPosition(); // update audio listener values - // set the viewer posotion in Cartesian coordinates in meters + // set the viewer position in Cartesian coordinates in meters smgr->set_position( abs_viewer_position, loop_view->getPosition() ); smgr->set_orientation( current_view_orientation ); diff --git a/src/MultiPlayer/mpmessages.hxx b/src/MultiPlayer/mpmessages.hxx index f5b89eb82..38e7fea58 100644 --- a/src/MultiPlayer/mpmessages.hxx +++ b/src/MultiPlayer/mpmessages.hxx @@ -164,7 +164,7 @@ struct FGExternalMotionData { // the earth centered frame SGVec3f angularAccel; - // The set of properties recieved for this timeslot + // The set of properties received for this timeslot std::vector<FGPropertyData*> properties; ~FGExternalMotionData() diff --git a/src/MultiPlayer/multiplaymgr.cxx b/src/MultiPlayer/multiplaymgr.cxx index 9a5413827..a8f862388 100644 --- a/src/MultiPlayer/multiplaymgr.cxx +++ b/src/MultiPlayer/multiplaymgr.cxx @@ -42,9 +42,11 @@ #include <simgear/props/props.hxx> #include <AIModel/AIManager.hxx> +#include <AIModel/AIMultiplayer.hxx> #include <Main/fg_props.hxx> #include "multiplaymgr.hxx" #include "mpmessages.hxx" +#include <FDM/flightProperties.hxx> using namespace std; @@ -56,11 +58,18 @@ using namespace std; const char sMULTIPLAYMGR_BID[] = "$Id$"; const char sMULTIPLAYMGR_HID[] = MULTIPLAYTXMGR_HID; +struct IdPropertyList { + unsigned id; + const char* name; + simgear::props::Type type; +}; + +static const IdPropertyList* findProperty(unsigned id); + // A static map of protocol property id values to property paths, // This should be extendable dynamically for every specific aircraft ... // For now only that static list -const FGMultiplayMgr::IdPropertyList -FGMultiplayMgr::sIdPropertyList[] = { +static const IdPropertyList sIdPropertyList[] = { {100, "surface-positions/left-aileron-pos-norm", simgear::props::FLOAT}, {101, "surface-positions/right-aileron-pos-norm", simgear::props::FLOAT}, {102, "surface-positions/elevator-pos-norm", simgear::props::FLOAT}, @@ -229,34 +238,33 @@ FGMultiplayMgr::sIdPropertyList[] = { {10319, "sim/multiplay/generic/int[19]", simgear::props::INT} }; -const unsigned -FGMultiplayMgr::numProperties = (sizeof(FGMultiplayMgr::sIdPropertyList) - / sizeof(FGMultiplayMgr::sIdPropertyList[0])); +const unsigned int numProperties = (sizeof(sIdPropertyList) + / sizeof(sIdPropertyList[0])); // Look up a property ID using binary search. namespace { struct ComparePropertyId { - bool operator()(const FGMultiplayMgr::IdPropertyList& lhs, - const FGMultiplayMgr::IdPropertyList& rhs) + bool operator()(const IdPropertyList& lhs, + const IdPropertyList& rhs) { return lhs.id < rhs.id; } - bool operator()(const FGMultiplayMgr::IdPropertyList& lhs, + bool operator()(const IdPropertyList& lhs, unsigned id) { return lhs.id < id; } bool operator()(unsigned id, - const FGMultiplayMgr::IdPropertyList& rhs) + const IdPropertyList& rhs) { return id < rhs.id; } - }; - + }; } -const FGMultiplayMgr::IdPropertyList* FGMultiplayMgr::findProperty(unsigned id) + +const IdPropertyList* findProperty(unsigned id) { std::pair<const IdPropertyList*, const IdPropertyList*> result = std::equal_range(sIdPropertyList, sIdPropertyList + numProperties, id, @@ -276,8 +284,7 @@ namespace const xdr_data_t* xdr = data; while (xdr < end) { unsigned id = XDR_decode_uint32(*xdr); - const FGMultiplayMgr::IdPropertyList* plist - = FGMultiplayMgr::findProperty(id); + const IdPropertyList* plist = findProperty(id); if (plist) { xdr++; @@ -336,6 +343,24 @@ namespace return true; } } + +class MPPropertyListener : public SGPropertyChangeListener +{ +public: + MPPropertyListener(FGMultiplayMgr* mp) : + _multiplay(mp) + { + } + + virtual void childAdded(SGPropertyNode*, SGPropertyNode*) + { + _multiplay->setPropertiesChanged(); + } + +private: + FGMultiplayMgr* _multiplay; +}; + ////////////////////////////////////////////////////////////////////// // // MultiplayMgr constructor @@ -343,9 +368,9 @@ namespace ////////////////////////////////////////////////////////////////////// FGMultiplayMgr::FGMultiplayMgr() { - mSocket = 0; mInitialised = false; mHaveServer = false; + mListener = NULL; } // FGMultiplayMgr::FGMultiplayMgr() ////////////////////////////////////////////////////////////////////// @@ -356,7 +381,7 @@ FGMultiplayMgr::FGMultiplayMgr() ////////////////////////////////////////////////////////////////////// FGMultiplayMgr::~FGMultiplayMgr() { - Close(); + } // FGMultiplayMgr::~FGMultiplayMgr() ////////////////////////////////////////////////////////////////////// @@ -375,22 +400,36 @@ FGMultiplayMgr::init (void) SG_LOG(SG_NETWORK, SG_WARN, "FGMultiplayMgr::init - already initialised"); return; } + + fgSetBool("/sim/multiplay/online", false); + ////////////////////////////////////////////////// // Set members from property values ////////////////////////////////////////////////// short rxPort = fgGetInt("/sim/multiplay/rxport"); string rxAddress = fgGetString("/sim/multiplay/rxhost"); - short txPort = fgGetInt("/sim/multiplay/txport"); + short txPort = fgGetInt("/sim/multiplay/txport", 5000); string txAddress = fgGetString("/sim/multiplay/txhost"); + + int hz = fgGetInt("/sim/multiplay/tx-rate-hz", 10); + if (hz < 1) { + hz = 10; + } + + mDt = 1.0 / hz; + mTimeUntilSend = 0.0; + mCallsign = fgGetString("/sim/multiplay/callsign"); - if (txPort > 0 && !txAddress.empty()) { + if (!txAddress.empty()) { mServer.set(txAddress.c_str(), txPort); if (strncmp (mServer.getHost(), "0.0.0.0", 8) == 0) { mHaveServer = false; - SG_LOG(SG_NETWORK, SG_DEBUG, + SG_LOG(SG_NETWORK, SG_WARN, "FGMultiplayMgr - could not resolve '" << txAddress << "', Multiplayermode disabled"); + return; } else { + SG_LOG(SG_NETWORK, SG_INFO, "have server"); mHaveServer = true; } if (rxPort <= 0) @@ -408,11 +447,10 @@ FGMultiplayMgr::init (void) SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-rxaddress="<<rxAddress ); SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-rxport= "<<rxPort); SG_LOG(SG_NETWORK,SG_INFO,"FGMultiplayMgr::init-callsign= "<<mCallsign); - Close(); // Should Init be called twice, close Socket first - // A memory leak was reported here by valgrind - mSocket = new simgear::Socket(); + + mSocket.reset(new simgear::Socket()); if (!mSocket->open(false)) { - SG_LOG( SG_NETWORK, SG_DEBUG, + SG_LOG( SG_NETWORK, SG_WARN, "FGMultiplayMgr::init - Failed to create data socket" ); return; } @@ -424,6 +462,11 @@ FGMultiplayMgr::init (void) return; } + mPropertiesChanged = true; + mListener = new MPPropertyListener(this); + globals->get_props()->addChangeListener(mListener, false); + + fgSetBool("/sim/multiplay/online", true); mInitialised = true; } // FGMultiplayMgr::init() ////////////////////////////////////////////////////////////////////// @@ -435,19 +478,39 @@ FGMultiplayMgr::init (void) // ////////////////////////////////////////////////////////////////////// void -FGMultiplayMgr::Close (void) +FGMultiplayMgr::shutdown (void) { - mMultiPlayerMap.clear(); - - if (mSocket) { + fgSetBool("/sim/multiplay/online", false); + + if (mSocket.get()) { mSocket->close(); - delete mSocket; - mSocket = 0; + mSocket.reset(); } + + MultiPlayerMap::iterator it = mMultiPlayerMap.begin(), + end = mMultiPlayerMap.end(); + for (; it != end; ++it) { + it->second->setDie(true); + } + mMultiPlayerMap.clear(); + + if (mListener) { + globals->get_props()->removeChangeListener(mListener); + delete mListener; + mListener = NULL; + } + mInitialised = false; } // FGMultiplayMgr::Close(void) ////////////////////////////////////////////////////////////////////// +void +FGMultiplayMgr::reinit() +{ + shutdown(); + init(); +} + ////////////////////////////////////////////////////////////////////// // // Description: Sends the position data for the local position. @@ -757,7 +820,7 @@ FGMultiplayMgr::SendTextMessage(const string &MsgText) // ////////////////////////////////////////////////////////////////////// void -FGMultiplayMgr::update(double) +FGMultiplayMgr::update(double dt) { if (!mInitialised) return; @@ -765,6 +828,14 @@ FGMultiplayMgr::update(double) /// Just for expiry long stamp = SGTimeStamp::now().getSeconds(); + ////////////////////////////////////////////////// + // Send if required + ////////////////////////////////////////////////// + mTimeUntilSend -= dt; + if (mTimeUntilSend <= 0.0) { + Send(); + } + ////////////////////////////////////////////////// // Read the receive socket and process any data ////////////////////////////////////////////////// @@ -813,7 +884,7 @@ FGMultiplayMgr::update(double) << "message has invalid protocol number!" ); break; } - if (MsgHdr->MsgLen != bytes) { + if (static_cast<ssize_t>(MsgHdr->MsgLen) != bytes) { SG_LOG(SG_NETWORK, SG_DEBUG, "FGMultiplayMgr::MP_ProcessData - " << "message from " << MsgHdr->Callsign << " has invalid length!"); break; @@ -854,6 +925,140 @@ FGMultiplayMgr::update(double) } // FGMultiplayMgr::ProcessData(void) ////////////////////////////////////////////////////////////////////// +void +FGMultiplayMgr::Send() +{ + using namespace simgear; + + findProperties(); + + // smooth the send rate, by adjusting based on the 'remainder' time, which + // is how -ve mTimeUntilSend is. Watch for large values and ignore them, + // however. + if ((mTimeUntilSend < 0.0) && (fabs(mTimeUntilSend) < mDt)) { + mTimeUntilSend = mDt + mTimeUntilSend; + } else { + mTimeUntilSend = mDt; + } + + double sim_time = globals->get_sim_time_sec(); + static double lastTime = 0.0; + + // SG_LOG(SG_GENERAL, SG_INFO, "actual dt=" << sim_time - lastTime); + lastTime = sim_time; + + FlightProperties ifce; + + // put together a motion info struct, you will get that later + // from FGInterface directly ... + FGExternalMotionData motionInfo; + + // The current simulation time we need to update for, + // note that the simulation time is updated before calling all the + // update methods. Thus it contains the time intervals *end* time. + // The FDM is already run, so the states belong to that time. + motionInfo.time = sim_time; + motionInfo.lag = mDt; + + // These are for now converted from lat/lon/alt and euler angles. + // But this should change in FGInterface ... + double lon = ifce.get_Longitude(); + double lat = ifce.get_Latitude(); + // first the aprioriate structure for the geodetic one + SGGeod geod = SGGeod::fromRadFt(lon, lat, ifce.get_Altitude()); + // Convert to cartesion coordinate + motionInfo.position = SGVec3d::fromGeod(geod); + + // The quaternion rotating from the earth centered frame to the + // horizontal local frame + SGQuatf qEc2Hl = SGQuatf::fromLonLatRad((float)lon, (float)lat); + // The orientation wrt the horizontal local frame + float heading = ifce.get_Psi(); + float pitch = ifce.get_Theta(); + float roll = ifce.get_Phi(); + SGQuatf hlOr = SGQuatf::fromYawPitchRoll(heading, pitch, roll); + // The orientation of the vehicle wrt the earth centered frame + motionInfo.orientation = qEc2Hl*hlOr; + + if (!globals->get_subsystem("flight")->is_suspended()) { + // velocities + motionInfo.linearVel = SG_FEET_TO_METER*SGVec3f(ifce.get_uBody(), + ifce.get_vBody(), + ifce.get_wBody()); + motionInfo.angularVel = SGVec3f(ifce.get_P_body(), + ifce.get_Q_body(), + ifce.get_R_body()); + + // accels, set that to zero for now. + // Angular accelerations are missing from the interface anyway, + // linear accelerations are screwed up at least for JSBSim. +// motionInfo.linearAccel = SG_FEET_TO_METER*SGVec3f(ifce.get_U_dot_body(), +// ifce.get_V_dot_body(), +// ifce.get_W_dot_body()); + motionInfo.linearAccel = SGVec3f::zeros(); + motionInfo.angularAccel = SGVec3f::zeros(); + } else { + // if the interface is suspendend, prevent the client from + // wild extrapolations + motionInfo.linearVel = SGVec3f::zeros(); + motionInfo.angularVel = SGVec3f::zeros(); + motionInfo.linearAccel = SGVec3f::zeros(); + motionInfo.angularAccel = SGVec3f::zeros(); + } + + // now send the properties + PropertyMap::iterator it; + for (it = mPropertyMap.begin(); it != mPropertyMap.end(); ++it) { + FGPropertyData* pData = new FGPropertyData; + pData->id = it->first; + pData->type = it->second->getType(); + + switch (pData->type) { + case props::INT: + case props::LONG: + case props::BOOL: + pData->int_value = it->second->getIntValue(); + break; + case props::FLOAT: + case props::DOUBLE: + pData->float_value = it->second->getFloatValue(); + break; + case props::STRING: + case props::UNSPECIFIED: + { + // FIXME: We assume unspecified are strings for the moment. + + const char* cstr = it->second->getStringValue(); + int len = strlen(cstr); + + if (len > 0) + { + pData->string_value = new char[len + 1]; + strcpy(pData->string_value, cstr); + } + else + { + // Size 0 - ignore + pData->string_value = 0; + } + + //cout << " Sending property " << pData->id << " " << pData->type << " " << pData->string_value << "\n"; + break; + } + default: + // FIXME Currently default to a float. + //cout << "Unknown type when iterating through props: " << pData->type << "\n"; + pData->float_value = it->second->getFloatValue(); + break; + } + + motionInfo.properties.push_back(pData); + } + + SendMyPosition(motionInfo); +} + + ////////////////////////////////////////////////////////////////////// // // handle a position message @@ -1101,3 +1306,29 @@ FGMultiplayMgr::getMultiplayer(const std::string& callsign) else return 0; } + +void +FGMultiplayMgr::findProperties() +{ + if (!mPropertiesChanged) { + return; + } + + mPropertiesChanged = false; + + for (unsigned i = 0; i < numProperties; ++i) { + const char* name = sIdPropertyList[i].name; + SGPropertyNode* pNode = globals->get_props()->getNode(name); + if (!pNode) { + continue; + } + + int id = sIdPropertyList[i].id; + if (mPropertyMap.find(id) != mPropertyMap.end()) { + continue; // already activated + } + + mPropertyMap[id] = pNode; + SG_LOG(SG_NETWORK, SG_DEBUG, "activating MP property:" << pNode->getPath()); + } +} diff --git a/src/MultiPlayer/multiplaymgr.hxx b/src/MultiPlayer/multiplaymgr.hxx index 8475c0ef1..42444f014 100644 --- a/src/MultiPlayer/multiplaymgr.hxx +++ b/src/MultiPlayer/multiplaymgr.hxx @@ -31,48 +31,51 @@ #define MULTIPLAYTXMGR_HID "$Id$" -#include "mpmessages.hxx" #include <string> #include <vector> +#include <memory> #include <simgear/compiler.h> #include <simgear/props/props.hxx> -#include <Main/globals.hxx> #include <simgear/io/raw_socket.hxx> #include <simgear/structure/subsystem_mgr.hxx> -#include <AIModel/AIMultiplayer.hxx> - -struct FGExternalMotionInfo; +struct FGExternalMotionData; +class MPPropertyListener; +struct T_MsgHdr; +class FGAIMultiplayer; class FGMultiplayMgr : public SGSubsystem { -public: - - struct IdPropertyList { - unsigned id; - const char* name; - simgear::props::Type type; - }; - static const IdPropertyList sIdPropertyList[]; - static const unsigned numProperties; - - static const IdPropertyList* findProperty(unsigned id); - +public: FGMultiplayMgr(); ~FGMultiplayMgr(); virtual void init(void); virtual void update(double dt); - void Close(void); + virtual void shutdown(void); + virtual void reinit(); + // transmitter - void SendMyPosition(const FGExternalMotionData& motionInfo); + void SendTextMessage(const string &sMsgText); // receiver private: + friend class MPPropertyListener; + + void setPropertiesChanged() + { + mPropertiesChanged = true; + } + + void findProperties(); + + void Send(); + void SendMyPosition(const FGExternalMotionData& motionInfo); + union MsgBuf; FGAIMultiplayer* addMultiplayer(const std::string& callsign, const std::string& modelName); @@ -87,11 +90,22 @@ private: typedef std::map<std::string, SGSharedPtr<FGAIMultiplayer> > MultiPlayerMap; MultiPlayerMap mMultiPlayerMap; - simgear::Socket* mSocket; + std::auto_ptr<simgear::Socket> mSocket; simgear::IPAddress mServer; bool mHaveServer; bool mInitialised; std::string mCallsign; + + // Map between the property id's from the multiplayers network packets + // and the property nodes + typedef std::map<unsigned int, SGSharedPtr<SGPropertyNode> > PropertyMap; + PropertyMap mPropertyMap; + + bool mPropertiesChanged; + MPPropertyListener* mListener; + + double mDt; // reciprocal of /sim/multiplay/tx-rate-hz + double mTimeUntilSend; }; #endif diff --git a/src/Network/CMakeLists.txt b/src/Network/CMakeLists.txt index 1f42c68c7..3f0e202c2 100644 --- a/src/Network/CMakeLists.txt +++ b/src/Network/CMakeLists.txt @@ -15,7 +15,6 @@ set(SOURCES jpg-httpd.cxx jsclient.cxx lfsglass.cxx - multiplay.cxx native.cxx native_ctrls.cxx native_fdm.cxx diff --git a/src/Network/Makefile.am b/src/Network/Makefile.am index 0935d3ca4..e4ecc3b10 100644 --- a/src/Network/Makefile.am +++ b/src/Network/Makefile.am @@ -9,8 +9,6 @@ else JPEG_SERVER = endif -MPLAYER_AS = multiplay.cxx multiplay.hxx - libNetwork_a_SOURCES = \ protocol.cxx protocol.hxx \ ATC-Main.cxx ATC-Main.hxx \ @@ -33,7 +31,6 @@ libNetwork_a_SOURCES = \ net_ctrls.hxx net_fdm.hxx net_fdm_mini.hxx net_gui.hxx \ nmea.cxx nmea.hxx \ opengc.cxx opengc.hxx opengc_data.hxx \ - $(MPLAYER_AS) \ props.cxx props.hxx \ pve.cxx pve.hxx \ ray.cxx ray.hxx \ diff --git a/src/Network/multiplay.cxx b/src/Network/multiplay.cxx deleted file mode 100644 index ddedccea8..000000000 --- a/src/Network/multiplay.cxx +++ /dev/null @@ -1,319 +0,0 @@ -// multiplay.cxx -- protocol object for multiplay in Flightgear -// -// Written by Diarmuid Tyson, started February 2003. -// diarmuid.tyson@airservicesaustralia.com -// -// With addtions by Vivian Meazza, January 2006 -// -// Copyright (C) 2003 Airservices Australia -// -// 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 <simgear/compiler.h> - -#include <cstring> -#include <iostream> -#include <map> -#include <string> - -#include <simgear/debug/logstream.hxx> -#include <simgear/math/SGMath.hxx> - -#include <FDM/flightProperties.hxx> -#include <MultiPlayer/mpmessages.hxx> - -#include "multiplay.hxx" - -using std::string; - - -// These constants are provided so that the ident command can list file versions. -const char sFG_MULTIPLAY_BID[] = "$Id$"; -const char sFG_MULTIPLAY_HID[] = FG_MULTIPLAY_HID; - -typedef std::set<std::string> string_set; - -class MPPropertyListener : public SGPropertyChangeListener -{ -public: - MPPropertyListener(FGMultiplay* mp) : - _multiplay(mp) - { - } - - virtual void childAdded(SGPropertyNode*, SGPropertyNode*) - { - _multiplay->setPropertiesChanged(); - } - -private: - FGMultiplay* _multiplay; -}; - -/****************************************************************** -* Name: FGMultiplay -* Description: Constructor. Initialises the protocol and stores -* host and port information. -******************************************************************/ -FGMultiplay::FGMultiplay (const string &dir, const int rate, const string &host, const int port) { - - set_hz(rate); - - set_direction(dir); - - if (get_direction() == SG_IO_IN) { - - fgSetInt("/sim/multiplay/rxport", port); - fgSetString("/sim/multiplay/rxhost", host.c_str()); - - } else if (get_direction() == SG_IO_OUT) { - - fgSetInt("/sim/multiplay/txport", port); - fgSetString("/sim/multiplay/txhost", host.c_str()); - - } - - mPropertiesChanged = true; -} - - -/****************************************************************** -* Name: ~FGMultiplay -* Description: Destructor. -******************************************************************/ -FGMultiplay::~FGMultiplay () { -} - - -/****************************************************************** -* Name: open -* Description: Enables the protocol. -******************************************************************/ -bool FGMultiplay::open() { - - if ( is_enabled() ) { - SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel " - << "is already in use, ignoring" ); - return false; - } - - set_enabled(true); - - mPropertiesChanged = true; - - MPPropertyListener* pl = new MPPropertyListener(this); - globals->get_props()->addChangeListener(pl, false); - return is_enabled(); -} - -void FGMultiplay::findProperties() -{ - if (!mPropertiesChanged) { - return; - } - - mPropertiesChanged = false; - - for (unsigned i = 0; i < FGMultiplayMgr::numProperties; ++i) { - const char* name = FGMultiplayMgr::sIdPropertyList[i].name; - SGPropertyNode* pNode = globals->get_props()->getNode(name); - if (!pNode) { - continue; - } - - int id = FGMultiplayMgr::sIdPropertyList[i].id; - if (mPropertyMap.find(id) != mPropertyMap.end()) { - continue; // already activated - } - - mPropertyMap[id] = pNode; - SG_LOG(SG_NETWORK, SG_INFO, "activating MP property:" << pNode->getPath()); - } - -} - - -/****************************************************************** -* Name: process -* Description: Prompts the multiplayer mgr to either send -* or receive data over the network -******************************************************************/ -bool FGMultiplay::process() { - using namespace simgear; - if (get_direction() == SG_IO_OUT) { - findProperties(); - - // check if we have left initialization phase. That will not provide - // interresting data, also the freeze in simulation time hurts the - // multiplayer clients - double sim_time = globals->get_sim_time_sec(); -// if (sim_time < 20) -// return true; - - FlightProperties ifce; - - // put together a motion info struct, you will get that later - // from FGInterface directly ... - FGExternalMotionData motionInfo; - - // The current simulation time we need to update for, - // note that the simulation time is updated before calling all the - // update methods. Thus it contains the time intervals *end* time. - // The FDM is already run, so the states belong to that time. - motionInfo.time = sim_time; - - // The typical lag will be the reciprocal of the output frequency - double hz = get_hz(); - if (hz != 0) // I guess we can test a double for exact zero in this case - motionInfo.lag = 1/get_hz(); - else - motionInfo.lag = 0.1; //?? - - // These are for now converted from lat/lon/alt and euler angles. - // But this should change in FGInterface ... - double lon = ifce.get_Longitude(); - double lat = ifce.get_Latitude(); - // first the aprioriate structure for the geodetic one - SGGeod geod = SGGeod::fromRadFt(lon, lat, ifce.get_Altitude()); - // Convert to cartesion coordinate - motionInfo.position = SGVec3d::fromGeod(geod); - - // The quaternion rotating from the earth centered frame to the - // horizontal local frame - SGQuatf qEc2Hl = SGQuatf::fromLonLatRad((float)lon, (float)lat); - // The orientation wrt the horizontal local frame - float heading = ifce.get_Psi(); - float pitch = ifce.get_Theta(); - float roll = ifce.get_Phi(); - SGQuatf hlOr = SGQuatf::fromYawPitchRoll(heading, pitch, roll); - // The orientation of the vehicle wrt the earth centered frame - motionInfo.orientation = qEc2Hl*hlOr; - - if (!globals->get_subsystem("flight")->is_suspended()) { - // velocities - motionInfo.linearVel = SG_FEET_TO_METER*SGVec3f(ifce.get_uBody(), - ifce.get_vBody(), - ifce.get_wBody()); - motionInfo.angularVel = SGVec3f(ifce.get_P_body(), - ifce.get_Q_body(), - ifce.get_R_body()); - - // accels, set that to zero for now. - // Angular accelerations are missing from the interface anyway, - // linear accelerations are screwed up at least for JSBSim. -// motionInfo.linearAccel = SG_FEET_TO_METER*SGVec3f(ifce.get_U_dot_body(), -// ifce.get_V_dot_body(), -// ifce.get_W_dot_body()); - motionInfo.linearAccel = SGVec3f::zeros(); - motionInfo.angularAccel = SGVec3f::zeros(); - } else { - // if the interface is suspendend, prevent the client from - // wild extrapolations - motionInfo.linearVel = SGVec3f::zeros(); - motionInfo.angularVel = SGVec3f::zeros(); - motionInfo.linearAccel = SGVec3f::zeros(); - motionInfo.angularAccel = SGVec3f::zeros(); - } - - // now send the properties - PropertyMap::iterator it; - for (it = mPropertyMap.begin(); it != mPropertyMap.end(); ++it) { - FGPropertyData* pData = new FGPropertyData; - pData->id = it->first; - pData->type = it->second->getType(); - - switch (pData->type) { - case props::INT: - case props::LONG: - case props::BOOL: - pData->int_value = it->second->getIntValue(); - break; - case props::FLOAT: - case props::DOUBLE: - pData->float_value = it->second->getFloatValue(); - break; - case props::STRING: - case props::UNSPECIFIED: - { - // FIXME: We assume unspecified are strings for the moment. - - const char* cstr = it->second->getStringValue(); - int len = strlen(cstr); - - if (len > 0) - { - pData->string_value = new char[len + 1]; - strcpy(pData->string_value, cstr); - } - else - { - // Size 0 - ignore - pData->string_value = 0; - } - - //cout << " Sending property " << pData->id << " " << pData->type << " " << pData->string_value << "\n"; - break; - } - default: - // FIXME Currently default to a float. - //cout << "Unknown type when iterating through props: " << pData->type << "\n"; - pData->float_value = it->second->getFloatValue(); - break; - } - - motionInfo.properties.push_back(pData); - } - - FGMultiplayMgr* mpmgr = (FGMultiplayMgr*) globals->get_subsystem("mp"); - mpmgr->SendMyPosition(motionInfo); - } - - return true; -} - - -/****************************************************************** -* Name: close -* Description: Closes the multiplayer mgrs to stop any further -* network processing -******************************************************************/ -bool FGMultiplay::close() -{ - mPropertyMap.clear(); - - FGMultiplayMgr* mgr = (FGMultiplayMgr*) globals->get_subsystem("mp"); - - if (mgr == 0) { - return false; - } - - if (get_direction() == SG_IO_IN) { - - mgr->Close(); - - } else if (get_direction() == SG_IO_OUT) { - - mgr->Close(); - - } - - return true; -} - diff --git a/src/Network/multiplay.hxx b/src/Network/multiplay.hxx deleted file mode 100644 index f596ea0eb..000000000 --- a/src/Network/multiplay.hxx +++ /dev/null @@ -1,97 +0,0 @@ -// multiplay.hxx -- protocol object for multiplay in Flightgear -// -// Written by Diarmuid Tyson, started February 2003. -// diarmuid.tyson@airservicesaustralia.com -// -// With additions by Vivian Meazza, January 2006 -// -// Copyright (C) 2003 Airservices Australia -// -// 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 _FG_MULTIPLAY_HXX -#define _FG_MULTIPLAY_HXX - -#define FG_MULTIPLAY_HID "$Id$" - -#include <simgear/compiler.h> - -#include <string> - -#include <simgear/props/props.hxx> - -#include <Main/globals.hxx> -#include <Main/fg_props.hxx> -#include <Model/acmodel.hxx> -#include <MultiPlayer/multiplaymgr.hxx> - -#include "protocol.hxx" - -using std::string; - - -/**************************************************************** -* @version $Id$ -* -* Description: FGMultiplay is an FGProtocol object used as the basic -* interface for the multiplayer code into FlightGears generic IO -* subsystem. It only implements the basic FGProtocol methods: open(), -* process() and close(). It does not use Sim Gear's IO channels, as -* the MultiplayMgrs creates their own sockets through plib. -* -* It will set up it's direction and rate protocol properties when -* created. Subsequent calls to process will prompt the -* MultiplayMgr to either send or receive data over the network. -* -******************************************************************/ - -class FGMultiplay : public FGProtocol { -public: - - /** Constructor */ - FGMultiplay (const string &dir, const int rate, const string &host, const int port); - - /** Destructor. */ - ~FGMultiplay (); - - /** Enables the FGMultiplay object. */ - bool open(); - - /** Tells the multiplayer_mgr to send/receive data. - */ - bool process(); - - /** Closes the multiplayer_mgr. - */ - bool close(); - - void setPropertiesChanged() - { - mPropertiesChanged = true; - } -private: - bool mPropertiesChanged; - - void findProperties(); - - // Map between the property id's from the multiplayers network packets - // and the property nodes - typedef std::map<unsigned, SGSharedPtr<SGPropertyNode> > PropertyMap; - PropertyMap mPropertyMap; -}; - - -#endif // _FG_MULTIPLAY_HXX diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index 62a2b261c..2690bda6d 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -805,10 +805,19 @@ void FGNasalSys::update(double) _context = naNewContext(); } +bool pathSortPredicate(const SGPath& p1, const SGPath& p2) +{ + return p1.file() < p2.file(); +} + // Loads all scripts in given directory void FGNasalSys::loadScriptDirectory(simgear::Dir nasalDir) { simgear::PathList scripts = nasalDir.children(simgear::Dir::TYPE_FILE, ".nas"); + // sort scripts, avoid loading sequence effects due to file system's + // random directory order + std::sort(scripts.begin(), scripts.end(), pathSortPredicate); + for (unsigned int i=0; i<scripts.size(); ++i) { SGPath fullpath(scripts[i]); SGPath file = fullpath.file(); diff --git a/src/Sound/sample_queue.cxx b/src/Sound/sample_queue.cxx index e5c2293a6..ac56c9b25 100644 --- a/src/Sound/sample_queue.cxx +++ b/src/Sound/sample_queue.cxx @@ -80,7 +80,7 @@ FGSampleQueue::update (double dt) last_volume = volume; } - // process mesage queue + // process message queue const string msgid = "Sequential Audio Message"; bool now_playing = false; if ( exists( msgid ) ) { diff --git a/src/Time/light.cxx b/src/Time/light.cxx index 348bd524d..79259c03c 100644 --- a/src/Time/light.cxx +++ b/src/Time/light.cxx @@ -345,7 +345,7 @@ void FGLight::update_adj_fog_color () { else hor_rotation = fmod(hor_rotation, SGD_2PI); - // revert to unmodified values before usign them. + // revert to unmodified values before using them. // SGVec4f color = thesky->get_scene_color(); @@ -359,7 +359,7 @@ void FGLight::update_adj_fog_color () { float s_green = color[1]*color[1]*color[1]; float s_blue = color[2]*color[2]; - // interpolate beween the sunrise/sunset color and the color + // interpolate between the sunrise/sunset color and the color // at the opposite direction of this effect. Take in account // the current visibility. //