1
0
Fork 0

Merge branch 'next' of gitorious.org:fg/flightgear into next

This commit is contained in:
Erik Hofman 2012-01-08 15:38:22 +01:00
commit 94e4d19ad1
8 changed files with 177 additions and 65 deletions

View file

@ -75,8 +75,7 @@ FGAIBase::FGAIBase(object_type ot, bool enableHot) :
_refID( _newAIModelID() ), _refID( _newAIModelID() ),
_otype(ot), _otype(ot),
_initialized(false), _initialized(false),
_aimodel(0), _modeldata(0),
_fxpath(""),
_fx(0) _fx(0)
{ {
@ -232,13 +231,19 @@ void FGAIBase::update(double dt) {
pitch*speed ); pitch*speed );
_fx->set_velocity( velocity ); _fx->set_velocity( velocity );
} }
else if ((_aimodel)&&(fgGetBool("/sim/sound/aimodels/enabled",false))) else if ((_modeldata)&&(_modeldata->needInitilization()))
{ {
string fxpath = _aimodel->get_sound_path(); // process deferred nasal initialization,
// which must be done in main thread
_modeldata->init();
// sound initialization
if (fgGetBool("/sim/sound/aimodels/enabled",false))
{
string fxpath = _modeldata->get_sound_path();
if (fxpath != "") if (fxpath != "")
{ {
_fxpath = fxpath; props->setStringValue("sim/sound/path", fxpath.c_str());
props->setStringValue("sim/sound/path", _fxpath.c_str());
// initialize the sound configuration // initialize the sound configuration
SGSoundMgr *smgr = globals->get_soundmgr(); SGSoundMgr *smgr = globals->get_soundmgr();
@ -249,6 +254,7 @@ void FGAIBase::update(double dt) {
_fx->init(); _fx->init();
} }
} }
}
} }
/** update LOD properties of the model */ /** update LOD properties of the model */
@ -324,8 +330,8 @@ bool FGAIBase::init(bool search_in_AI_path)
else else
_installed = true; _installed = true;
_aimodel = new FGAIModelData(props); _modeldata = new FGAIModelData(props);
osg::Node * mdl = SGModelLib::loadDeferredModel(f, props, _aimodel); osg::Node * mdl = SGModelLib::loadDeferredModel(f, props, _modeldata);
_model = new osg::LOD; _model = new osg::LOD;
_model->setName("AI-model range animation node"); _model->setName("AI-model range animation node");
@ -912,7 +918,8 @@ int FGAIBase::_newAIModelID() {
FGAIModelData::FGAIModelData(SGPropertyNode *root) FGAIModelData::FGAIModelData(SGPropertyNode *root)
: _nasal( new FGNasalModelData(root) ), : _nasal( new FGNasalModelData(root) ),
_path("") _ready(false),
_initialized(false)
{ {
} }
@ -923,9 +930,21 @@ FGAIModelData::~FGAIModelData()
void FGAIModelData::modelLoaded(const string& path, SGPropertyNode *prop, osg::Node *n) void FGAIModelData::modelLoaded(const string& path, SGPropertyNode *prop, osg::Node *n)
{ {
const char* fxpath = prop->getStringValue("sound/path"); // WARNING: All this is called in a separate OSG thread! Only use thread-safe stuff
if (fxpath) { // here that is fine to be run concurrently with stuff in the main loop!
_path = string(fxpath); if (_ready)
} return;
_nasal->modelLoaded(path, prop, n); _fxpath = _prop->getStringValue("sound/path");
_prop = prop;
_path = path;
_ready = true;
}
// do Nasal initialization (must be called in the main loop)
void FGAIModelData::init()
{
// call FGNasalSys to create context and run hooks (not-thread safe!)
_nasal->modelLoaded(_path, _prop, 0);
_prop = 0;
_initialized = true;
} }

View file

@ -21,7 +21,6 @@
#define _FG_AIBASE_HXX #define _FG_AIBASE_HXX
#include <string> #include <string>
#include <list>
#include <simgear/constants.h> #include <simgear/constants.h>
#include <simgear/math/SGMath.hxx> #include <simgear/math/SGMath.hxx>
@ -38,7 +37,6 @@
using std::string; using std::string;
using std::list;
class SGMaterial; class SGMaterial;
class FGAIManager; class FGAIManager;
@ -230,9 +228,8 @@ private:
bool _initialized; bool _initialized;
osg::ref_ptr<osg::LOD> _model; //The 3D model LOD object osg::ref_ptr<osg::LOD> _model; //The 3D model LOD object
osg::ref_ptr<FGAIModelData> _aimodel; osg::ref_ptr<FGAIModelData> _modeldata;
string _fxpath;
SGSharedPtr<FGFX> _fx; SGSharedPtr<FGFX> _fx;
public: public:
@ -453,12 +450,24 @@ class FGAIModelData : public simgear::SGModelData {
public: public:
FGAIModelData(SGPropertyNode *root = 0); FGAIModelData(SGPropertyNode *root = 0);
~FGAIModelData(); ~FGAIModelData();
/** osg callback, thread-safe */
void modelLoaded(const string& path, SGPropertyNode *prop, osg::Node *n); void modelLoaded(const string& path, SGPropertyNode *prop, osg::Node *n);
inline string& get_sound_path() { return _path; };
/** init hook to be called after model is loaded.
* Not thread-safe. Call from main thread only. */
void init(void);
bool needInitilization(void) { return _ready && !_initialized;}
bool isInitialized(void) { return _initialized;}
inline std::string& get_sound_path() { return _fxpath;}
private: private:
FGNasalModelData *_nasal; FGNasalModelData *_nasal;
string _path; SGPropertyNode_ptr _prop;
std::string _path, _fxpath;
bool _ready;
bool _initialized;
}; };
#endif // _FG_AIBASE_HXX #endif // _FG_AIBASE_HXX

View file

@ -580,9 +580,23 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
} }
FGTaxiNode *firstNode = findNode(start); FGTaxiNode *firstNode = findNode(start);
if (!firstNode)
{
SG_LOG(SG_GENERAL, SG_ALERT,
"Error in ground network. Failed to find first waypoint: " << start
<< " at " << ((parent) ? parent->getId() : "<unknown>"));
return FGTaxiRoute();
}
firstNode->setPathScore(0); firstNode->setPathScore(0);
FGTaxiNode *lastNode = findNode(end); FGTaxiNode *lastNode = findNode(end);
if (!lastNode)
{
SG_LOG(SG_GENERAL, SG_ALERT,
"Error in ground network. Failed to find last waypoint: " << end
<< " at " << ((parent) ? parent->getId() : "<unknown>"));
return FGTaxiRoute();
}
FGTaxiNodeVector unvisited(*currNodesSet); // working copy FGTaxiNodeVector unvisited(*currNodesSet); // working copy
@ -606,6 +620,13 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
seg != best->getEndRoute(); seg++) { seg != best->getEndRoute(); seg++) {
if (fullSearch || (*seg)->isPushBack()) { if (fullSearch || (*seg)->isPushBack()) {
FGTaxiNode *tgt = (*seg)->getEnd(); FGTaxiNode *tgt = (*seg)->getEnd();
if (!tgt)
{
SG_LOG(SG_GENERAL, SG_ALERT,
"Error in ground network. Found empty segment "
<< " at " << ((parent) ? parent->getId() : "<unknown>"));
return FGTaxiRoute();
}
double alt = double alt =
best->getPathScore() + (*seg)->getLength() + best->getPathScore() + (*seg)->getLength() +
(*seg)->getPenalty(nParkings); (*seg)->getPenalty(nParkings);

View file

@ -8,6 +8,7 @@
#include <simgear/props/props_io.hxx> #include <simgear/props/props_io.hxx>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/structure/SGBinding.hxx> #include <simgear/structure/SGBinding.hxx>
#include <simgear/misc/strutils.hxx>
#include <Main/fg_props.hxx> #include <Main/fg_props.hxx>
@ -16,6 +17,7 @@
using std::string; using std::string;
using std::map; using std::map;
using std::cout; using std::cout;
using namespace simgear;
typedef std::map<NSMenuItem*, SGBindingList> MenuItemBindings; typedef std::map<NSMenuItem*, SGBindingList> MenuItemBindings;
@ -27,7 +29,6 @@ public:
CocoaMenuBarPrivate(); CocoaMenuBarPrivate();
~CocoaMenuBarPrivate(); ~CocoaMenuBarPrivate();
bool labelIsSeparator(const std::string& s) const;
void menuFromProps(NSMenu* menu, SGPropertyNode* menuNode); void menuFromProps(NSMenu* menu, SGPropertyNode* menuNode);
void fireBindingsForItem(NSMenuItem* item); void fireBindingsForItem(NSMenuItem* item);
@ -63,6 +64,51 @@ static NSString* stdStringToCocoa(const string& s)
return [NSString stringWithUTF8String:s.c_str()]; return [NSString stringWithUTF8String:s.c_str()];
} }
static void setFunctionKeyShortcut(NSMenuItem* item, unichar shortcut)
{
unichar ch[1];
ch[0] = shortcut;
[item setKeyEquivalentModifierMask:NSFunctionKeyMask];
[item setKeyEquivalent:[NSString stringWithCharacters:ch length:1]];
}
static void setItemShortcutFromString(NSMenuItem* item, const string& s)
{
const char* shortcut = "";
bool hasCtrl = strutils::starts_with(s, "Ctrl-");
bool hasShift = strutils::starts_with(s, "Shift-");
bool hasAlt = strutils::starts_with(s, "Alt-");
int offset = 0; // character offset from start of string
if (hasShift) offset += 6;
if (hasCtrl) offset += 5;
if (hasAlt) offset += 4;
shortcut = s.c_str() + offset;
if (!strcmp(shortcut, "Esc"))
shortcut = "\e";
if (!strcmp(shortcut, "F11")) {
setFunctionKeyShortcut(item, NSF11FunctionKey);
return;
}
if (!strcmp(shortcut, "F12")) {
setFunctionKeyShortcut(item, NSF12FunctionKey);
return;
}
[item setKeyEquivalent:[NSString stringWithCString:shortcut encoding:NSUTF8StringEncoding]];
NSUInteger modifiers = 0;
if (hasCtrl) modifiers |= NSControlKeyMask;
if (hasShift) modifiers |= NSShiftKeyMask;
if (hasAlt) modifiers |= NSAlternateKeyMask;
[item setKeyEquivalentModifierMask:modifiers];
}
class EnabledListener : public SGPropertyChangeListener class EnabledListener : public SGPropertyChangeListener
{ {
public: public:
@ -94,15 +140,9 @@ FGCocoaMenuBar::CocoaMenuBarPrivate::~CocoaMenuBarPrivate()
[delegate release]; [delegate release];
} }
bool FGCocoaMenuBar::CocoaMenuBarPrivate::labelIsSeparator(const std::string& s) const static bool labelIsSeparator(NSString* s)
{ {
for (unsigned int i=0; i<s.size(); ++i) { return [s hasPrefix:@"---"];
if (s[i] != '-') {
return false;
}
}
return true;
} }
void FGCocoaMenuBar::CocoaMenuBarPrivate::menuFromProps(NSMenu* menu, SGPropertyNode* menuNode) void FGCocoaMenuBar::CocoaMenuBarPrivate::menuFromProps(NSMenu* menu, SGPropertyNode* menuNode)
@ -113,21 +153,28 @@ void FGCocoaMenuBar::CocoaMenuBarPrivate::menuFromProps(NSMenu* menu, SGProperty
n->setBoolValue("enabled", true); n->setBoolValue("enabled", true);
} }
string shortcut;
string l = n->getStringValue("label"); string l = n->getStringValue("label");
string::size_type pos = l.find("("); string::size_type pos = l.find("(");
if (pos != string::npos) { if (pos != string::npos) {
l = l.substr(0, pos); string full(l);
l = full.substr(0, pos);
shortcut = full.substr(pos + 1, full.size() - (pos + 2));
} }
NSString* label = stdStringToCocoa(l); NSString* label = stdStringToCocoa(strutils::simplify(l));
NSString* shortcut = @"";
NSMenuItem* item; NSMenuItem* item;
if (index >= [menu numberOfItems]) { if (index >= [menu numberOfItems]) {
if (labelIsSeparator(l)) { if (labelIsSeparator(label)) {
item = [NSMenuItem separatorItem]; item = [NSMenuItem separatorItem];
[menu addItem:item]; [menu addItem:item];
} else { } else {
item = [menu addItemWithTitle:label action:nil keyEquivalent:shortcut]; item = [menu addItemWithTitle:label action:nil keyEquivalent:@""];
if (!shortcut.empty()) {
setItemShortcutFromString(item, shortcut);
}
n->getNode("enabled")->addChangeListener(new EnabledListener(item)); n->getNode("enabled")->addChangeListener(new EnabledListener(item));
[item setTarget:delegate]; [item setTarget:delegate];
[item setAction:@selector(itemAction:)]; [item setAction:@selector(itemAction:)];

View file

@ -1123,6 +1123,16 @@ void NavDisplay::computePositionedState(FGPositioned* pos, string_set& states)
} // FGPositioned::Type switch } // FGPositioned::Type switch
} }
static string mapAINodeToType(SGPropertyNode* model)
{
// assume all multiplayer items are aircraft for the moment. Not ideal.
if (!strcmp(model->getName(), "multiplayer")) {
return "ai-aircraft";
}
return string("ai-") + model->getName();
}
void NavDisplay::processAI() void NavDisplay::processAI()
{ {
SGPropertyNode *ai = fgGetNode("/ai/models", true); SGPropertyNode *ai = fgGetNode("/ai/models", true);
@ -1137,7 +1147,7 @@ void NavDisplay::processAI()
string_set ss; string_set ss;
computeAIStates(model, ss); computeAIStates(model, ss);
SymbolDefVector rules; SymbolDefVector rules;
findRules(string("ai-") + model->getName(), ss, rules); findRules(mapAINodeToType(model), ss, rules);
if (rules.empty()) { if (rules.empty()) {
return; // no rules matched, we can skip this item return; // no rules matched, we can skip this item
} }
@ -1160,13 +1170,14 @@ void NavDisplay::processAI()
void NavDisplay::computeAIStates(const SGPropertyNode* ai, string_set& states) void NavDisplay::computeAIStates(const SGPropertyNode* ai, string_set& states)
{ {
int threatLevel = ai->getIntValue("tcas/threat-level",-1); int threatLevel = ai->getIntValue("tcas/threat-level",-1);
if (threatLevel >= 0) { if (threatLevel < 1)
threatLevel = 0;
states.insert("tcas"); states.insert("tcas");
std::ostringstream os; std::ostringstream os;
os << "tcas-threat-level-" << threatLevel; os << "tcas-threat-level-" << threatLevel;
states.insert(os.str()); states.insert(os.str());
}
double vspeed = ai->getDoubleValue("velocities/vertical-speed-fps"); double vspeed = ai->getDoubleValue("velocities/vertical-speed-fps");
if (vspeed < -3.0) { if (vspeed < -3.0) {

View file

@ -502,7 +502,7 @@ static SGPath platformDefaultDataPath()
SGPath appData; SGPath appData;
appData.set((const char*) path); appData.set((const char*) path);
appData.append("flightgear.org"); appData.append("FlightGear");
return appData; return appData;
} }
#else #else

View file

@ -365,11 +365,8 @@ getMagDip ()
static double static double
getHeadingMag () getHeadingMag ()
{ {
double magheading; double magheading = fgGetDouble("/orientation/heading-deg") - getMagVar();
magheading = fgGetDouble("/orientation/heading-deg") - getMagVar(); return SGMiscd::normalizePeriodic(0.5, 360.5, magheading );
if (magheading <= 0) magheading += 360;
else if (magheading > 360) magheading -= 360;
return magheading;
} }
/** /**
@ -378,11 +375,8 @@ getHeadingMag ()
static double static double
getTrackMag () getTrackMag ()
{ {
double magtrack; double magtrack = fgGetDouble("/orientation/track-deg") - getMagVar();
magtrack = fgGetDouble("/orientation/track-deg") - getMagVar(); return SGMiscd::normalizePeriodic(0.5, 360.5, magtrack );
if (magtrack <= 0) magtrack += 360;
else if (magtrack > 360) magtrack -= 360;
return magtrack;
} }
static bool static bool

View file

@ -247,9 +247,20 @@ FGTileMgr::loadTileModel(const string& modelPath, bool cacheModel)
SGModelLib::loadModel(fullPath.str(), globals->get_props(), SGModelLib::loadModel(fullPath.str(), globals->get_props(),
new FGNasalModelData); new FGNasalModelData);
else else
{
/* TODO FGNasalModelData's callback "modelLoaded" isn't thread-safe.
* But deferred (or paged) OSG loading runs in a separate thread, which would
* trigger the FGNasalModelData::modelLoaded callback. We're easily doomed
* when this happens and the model actually contains a Nasal "load" hook - which
* would run the Nasal parser and Nasal script execution in a separate thread...
* => Disabling the callback for now, to test if all Nasal related segfaults are
* gone. Proper resolution is TBD. We'll need to somehow decouple the OSG callback,
* so we can run the Nasal stuff in the main thread.
*/
result= result=
SGModelLib::loadDeferredModel(fullPath.str(), globals->get_props(), SGModelLib::loadDeferredModel(fullPath.str(), globals->get_props()/*,
new FGNasalModelData); new FGNasalModelData*/);
}
} catch (const sg_io_exception& exc) { } catch (const sg_io_exception& exc) {
string m(exc.getMessage()); string m(exc.getMessage());
m += " "; m += " ";