X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FAIModel%2FAIBase.cxx;h=7cfcfcb0a33418517ff24f767da13d599e186191;hb=bcea720db3e29a62626b361f2149a7147e149f3b;hp=d143296a18f04b8f931701721924fb4bf5634fd8;hpb=52ac173257bf9cc780f0faee5049314442083140;p=flightgear.git diff --git a/src/AIModel/AIBase.cxx b/src/AIModel/AIBase.cxx index d143296a1..7cfcfcb0a 100644 --- a/src/AIModel/AIBase.cxx +++ b/src/AIModel/AIBase.cxx @@ -24,6 +24,8 @@ # include #endif +#include + #include #include @@ -32,16 +34,17 @@ #include #include -#include #include #include #include +#include #include #include #include
#include #include +#include #include "AIBase.hxx" #include "AIManager.hxx" @@ -52,12 +55,15 @@ const double FGAIBase::lbs_to_slugs = 0.031080950172; //conversion factor using namespace simgear; -FGAIBase::FGAIBase(object_type ot) : +FGAIBase::FGAIBase(object_type ot, bool enableHot) : + _max_speed(300), + _name(""), + _parent(""), props( NULL ), model_removed( fgGetNode("/ai/models/model-removed", true) ), manager( NULL ), + _installed(false), fp( NULL ), - _impact_lat(0), _impact_lon(0), _impact_elev(0), @@ -65,10 +71,12 @@ FGAIBase::FGAIBase(object_type ot) : _impact_pitch(0), _impact_roll(0), _impact_speed(0), - _refID( _newAIModelID() ), _otype(ot), - _initialized(false) + _initialized(false), + _modeldata(0), + _fx(0) + { tgt_heading = hdg = tgt_altitude_ft = tgt_speed = 0.0; tgt_roll = roll = tgt_pitch = tgt_yaw = tgt_vs = vs = pitch = 0.0; @@ -81,7 +89,7 @@ FGAIBase::FGAIBase(object_type ot) : delete_me = false; _impact_reported = false; _collision_reported = false; - _expiry_reported = false; + _expiry_reported = false; _subID = 0; @@ -118,13 +126,15 @@ FGAIBase::FGAIBase(object_type ot) : p = 1e5; a = 340; Mach = 0; + + // explicitly disable HOT for (most) AI models + if (!enableHot) + aip.getSceneGraph()->setNodeMask(~SG_NODEMASK_TERRAIN_BIT); } FGAIBase::~FGAIBase() { // Unregister that one at the scenery manager - if (globals->get_scenery()) { - globals->get_scenery()->get_scene_graph()->removeChild(aip.getSceneGraph()); - } + removeModel(); if (props) { SGPropertyNode* parent = props->getParent(); @@ -132,10 +142,51 @@ FGAIBase::~FGAIBase() { if (parent) model_removed->setStringValue(props->getPath()); } - delete fp; + + // refID=0 is supposedley impossible, refID=1 is the special ai_ac aircaft + // representing the current user, in the ATCManager. Maybe both these + // tests could die? + if (_fx && _refID != 0 && _refID != 1) { + SGSoundMgr *smgr = globals->get_soundmgr(); + if (smgr) { + stringstream name; + name << "aifx:"; + name << _refID; + smgr->remove(name.str()); + } + } + + if (fp) + delete fp; fp = 0; } +/** Cleanly remove the model + * and let the scenery database pager do the clean-up work. + */ +void +FGAIBase::removeModel() +{ + if (!_model.valid()) + return; + + FGScenery* pSceneryManager = globals->get_scenery(); + if (pSceneryManager) + { + osg::ref_ptr temp = _model.get(); + pSceneryManager->get_scene_graph()->removeChild(aip.getSceneGraph()); + // withdraw from SGModelPlacement and drop own reference (unref) + aip.init( 0 ); + _model = 0; + // pass it on to the pager, to be be deleted in the pager thread + pSceneryManager->getPager()->queueDeleteRequest(temp); + } + else + { + SG_LOG(SG_AI, SG_ALERT, "AIBase: Could not unload model. Missing scenery manager!"); + } +} + void FGAIBase::readFromScenario(SGPropertyNode* scFileNode) { if (!scFileNode) @@ -170,6 +221,64 @@ void FGAIBase::update(double dt) { ft_per_deg_lat = 366468.96 - 3717.12 * cos(pos.getLatitudeRad()); ft_per_deg_lon = 365228.16 * cos(pos.getLatitudeRad()); + + if ( _fx ) + { + // update model's audio sample values + _fx->set_position_geod( pos ); + + SGQuatd orient = SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll); + _fx->set_orientation( orient ); + + SGVec3d velocity; + velocity = SGVec3d( speed_north_deg_sec, speed_east_deg_sec, + pitch*speed ); + _fx->set_velocity( velocity ); + } + else if ((_modeldata)&&(_modeldata->needInitilization())) + { + // 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 != "") + { + props->setStringValue("sim/sound/path", fxpath.c_str()); + + // initialize the sound configuration + stringstream name; + name << "aifx:"; + name << _refID; + _fx = new FGFX(name.str(), props); + _fx->init(); + } + } + } +} + +/** update LOD properties of the model */ +void FGAIBase::updateLOD() +{ + double maxRangeDetail = fgGetDouble("/sim/rendering/static-lod/ai-detailed", 10000.0); + double maxRangeBare = fgGetDouble("/sim/rendering/static-lod/ai-bare", 20000.0); + if (_model.valid()) + { + if( maxRangeDetail == 0.0 ) + { + // disable LOD + _model->setRange(0, 0.0, FLT_MAX); + _model->setRange(1, FLT_MAX, FLT_MAX); + } + else + { + _model->setRange(0, 0.0, maxRangeDetail); + _model->setRange(1, maxRangeDetail,maxRangeBare); + } + } } void FGAIBase::Transform() { @@ -191,33 +300,68 @@ void FGAIBase::Transform() { } -bool FGAIBase::init(bool search_in_AI_path) { - osg::ref_ptr opt= - new osgDB::ReaderWriter::Options(*osgDB::Registry::instance()->getOptions()); +bool FGAIBase::init(bool search_in_AI_path) +{ + if (_model.valid()) + { + SG_LOG(SG_AI, SG_ALERT, "AIBase: Cannot initialize a model multiple times! " << model_path); + return false; + } + string f; if(search_in_AI_path) { - SGPath ai_path(globals->get_fg_root()); - ai_path.append("AI"); - opt->getDatabasePathList().push_front(ai_path.str()); + // setup a modified Options structure, with only the $fg-root/AI defined; + // we'll check that first, then give the normal search logic a chance. + // this ensures that models in AI/ are preferred to normal models, where + // both exist. + osg::ref_ptr + opt(osg::clone(osgDB::Registry::instance()->getOptions(), osg::CopyOp::SHALLOW_COPY)); + + SGPath ai_path(globals->get_fg_root(), "AI"); + opt->setDatabasePath(ai_path.str()); + + f = osgDB::findDataFile(model_path, opt.get()); } - string f = osgDB::findDataFile(model_path, opt.get()); - + if (f.empty()) { + f = simgear::SGModelLib::findDataFile(model_path); + } + if(f.empty()) f = fgGetString("/sim/multiplay/default-model", default_model); - - model = load3DModel(f, props); - - if (model.valid() && _initialized == false) { - aip.init( model.get() ); + else + _installed = true; + + _modeldata = new FGAIModelData(props); + osg::Node * mdl = SGModelLib::loadDeferredModel(f, props, _modeldata); + + _model = new osg::LOD; + _model->setName("AI-model range animation node"); + + _model->addChild( mdl, 0, FLT_MAX ); + _model->setCenterMode(osg::LOD::USE_BOUNDING_SPHERE_CENTER); + _model->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT); +// We really need low-resolution versions of AI/MP aircraft. +// Or at least dummy "stubs" with some default silhouette. +// _model->addChild( SGModelLib::loadPagedModel(fgGetString("/sim/multiplay/default-model", default_model), +// props, new FGNasalModelData(props)), FLT_MAX, FLT_MAX); + updateLOD(); + + initModel(mdl); + if (_model.valid() && _initialized == false) { + aip.init( _model.get() ); aip.setVisible(true); invisible = false; globals->get_scenery()->get_scene_graph()->addChild(aip.getSceneGraph()); _initialized = true; + SG_LOG(SG_AI, SG_DEBUG, "AIBase: Loaded model " << model_path); + } else if (!model_path.empty()) { - SG_LOG(SG_INPUT, SG_WARN, "AIBase: Could not load model " << model_path); + SG_LOG(SG_AI, SG_WARN, "AIBase: Could not load model " << model_path); + // not properly installed... + _installed = false; } setDie(false); @@ -226,87 +370,88 @@ bool FGAIBase::init(bool search_in_AI_path) { void FGAIBase::initModel(osg::Node *node) { - if (model.valid()) { + if (_model.valid()) { - fgSetString("/ai/models/model-added", props->getPath().c_str()); + if( _path != ""){ + props->setStringValue("submodels/path", _path.c_str()); + SG_LOG(SG_AI, SG_DEBUG, "AIBase: submodels/path " << _path); + } + + if( _parent!= ""){ + props->setStringValue("parent-name", _parent.c_str()); + } + fgSetString("/ai/models/model-added", props->getPath().c_str()); } else if (!model_path.empty()) { - SG_LOG(SG_INPUT, SG_WARN, "AIBase: Could not load model " << model_path); + SG_LOG(SG_AI, SG_WARN, "AIBase: Could not load model " << model_path); } - props->setStringValue("submodels/path", _path.c_str()); setDie(false); } -osg::Node* FGAIBase::load3DModel(const string &path, SGPropertyNode *prop_root) -{ - model = SGModelLib::loadPagedModel(path, prop_root, new FGNasalModelData(prop_root)); - initModel(model.get()); - return model.get(); -} - bool FGAIBase::isa( object_type otype ) { return otype == _otype; } void FGAIBase::bind() { - props->tie("id", SGRawValueMethods(*this, + _tiedProperties.setRoot(props); + tie("id", SGRawValueMethods(*this, &FGAIBase::getID)); - props->tie("velocities/true-airspeed-kt", SGRawValuePointer(&speed)); - props->tie("velocities/vertical-speed-fps", + tie("velocities/true-airspeed-kt", SGRawValuePointer(&speed)); + tie("velocities/vertical-speed-fps", SGRawValueMethods(*this, &FGAIBase::_getVS_fps, &FGAIBase::_setVS_fps)); - props->tie("position/altitude-ft", + tie("position/altitude-ft", SGRawValueMethods(*this, &FGAIBase::_getAltitude, &FGAIBase::_setAltitude)); - props->tie("position/latitude-deg", + tie("position/latitude-deg", SGRawValueMethods(*this, &FGAIBase::_getLatitude, &FGAIBase::_setLatitude)); - props->tie("position/longitude-deg", + tie("position/longitude-deg", SGRawValueMethods(*this, &FGAIBase::_getLongitude, &FGAIBase::_setLongitude)); - props->tie("position/global-x", + tie("position/global-x", SGRawValueMethods(*this, &FGAIBase::_getCartPosX, 0)); - props->tie("position/global-y", + tie("position/global-y", SGRawValueMethods(*this, &FGAIBase::_getCartPosY, 0)); - props->tie("position/global-z", + tie("position/global-z", SGRawValueMethods(*this, &FGAIBase::_getCartPosZ, 0)); - props->tie("callsign", + tie("callsign", SGRawValueMethods(*this, &FGAIBase::_getCallsign, 0)); - props->tie("orientation/pitch-deg", SGRawValuePointer(&pitch)); - props->tie("orientation/roll-deg", SGRawValuePointer(&roll)); - props->tie("orientation/true-heading-deg", SGRawValuePointer(&hdg)); - - props->tie("radar/in-range", SGRawValuePointer(&in_range)); - props->tie("radar/bearing-deg", SGRawValuePointer(&bearing)); - props->tie("radar/elevation-deg", SGRawValuePointer(&elevation)); - props->tie("radar/range-nm", SGRawValuePointer(&range)); - props->tie("radar/h-offset", SGRawValuePointer(&horiz_offset)); - props->tie("radar/v-offset", SGRawValuePointer(&vert_offset)); - props->tie("radar/x-shift", SGRawValuePointer(&x_shift)); - props->tie("radar/y-shift", SGRawValuePointer(&y_shift)); - props->tie("radar/rotation", SGRawValuePointer(&rotation)); - props->tie("radar/ht-diff-ft", SGRawValuePointer(&ht_diff)); - props->tie("subID", SGRawValuePointer(&_subID)); - props->tie("controls/lighting/nav-lights", - SGRawValueFunctions(_isNight)); + tie("orientation/pitch-deg", SGRawValuePointer(&pitch)); + tie("orientation/roll-deg", SGRawValuePointer(&roll)); + tie("orientation/true-heading-deg", SGRawValuePointer(&hdg)); + + tie("radar/in-range", SGRawValuePointer(&in_range)); + tie("radar/bearing-deg", SGRawValuePointer(&bearing)); + tie("radar/elevation-deg", SGRawValuePointer(&elevation)); + tie("radar/range-nm", SGRawValuePointer(&range)); + tie("radar/h-offset", SGRawValuePointer(&horiz_offset)); + tie("radar/v-offset", SGRawValuePointer(&vert_offset)); + tie("radar/x-shift", SGRawValuePointer(&x_shift)); + tie("radar/y-shift", SGRawValuePointer(&y_shift)); + tie("radar/rotation", SGRawValuePointer(&rotation)); + tie("radar/ht-diff-ft", SGRawValuePointer(&ht_diff)); + tie("subID", SGRawValuePointer(&_subID)); + tie("controls/lighting/nav-lights", SGRawValueFunctions(_isNight)); + props->setBoolValue("controls/lighting/beacon", true); props->setBoolValue("controls/lighting/strobe", true); props->setBoolValue("controls/glide-path", true); @@ -319,42 +464,21 @@ void FGAIBase::bind() { props->setDoubleValue("controls/flight/target-alt", altitude_ft); props->setDoubleValue("controls/flight/target-pitch", pitch); - props->setDoubleValue("controls/flight/target-spd", speed); + props->setDoubleValue("controls/flight/target-spd", speed); + props->setBoolValue("sim/sound/avionics/enabled", false); + props->setDoubleValue("sim/sound/avionics/volume", 0.0); + props->setBoolValue("sim/sound/avionics/external-view", false); + props->setBoolValue("sim/current-view/internal", false); } void FGAIBase::unbind() { - props->untie("id"); - props->untie("velocities/true-airspeed-kt"); - props->untie("velocities/vertical-speed-fps"); - - props->untie("position/altitude-ft"); - props->untie("position/latitude-deg"); - props->untie("position/longitude-deg"); - props->untie("position/global-x"); - props->untie("position/global-y"); - props->untie("position/global-z"); - props->untie("callsign"); - - props->untie("orientation/pitch-deg"); - props->untie("orientation/roll-deg"); - props->untie("orientation/true-heading-deg"); - - props->untie("radar/in-range"); - props->untie("radar/bearing-deg"); - props->untie("radar/elevation-deg"); - props->untie("radar/range-nm"); - props->untie("radar/h-offset"); - props->untie("radar/v-offset"); - props->untie("radar/x-shift"); - props->untie("radar/y-shift"); - props->untie("radar/rotation"); - props->untie("radar/ht-diff-ft"); - - props->untie("controls/lighting/nav-lights"); + _tiedProperties.Untie(); - props->setBoolValue("/sim/controls/radar/", true); + props->setBoolValue("/sim/controls/radar", true); + // drop reference to sound effects now + _fx = 0; } double FGAIBase::UpdateRadar(FGAIManager* manager) { @@ -472,7 +596,7 @@ SGVec3d FGAIBase::getCartPosAt(const SGVec3d& _off) const { hlTrans *= SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll); // The offset converted to the usual body fixed coordinate system - // rotated to the earth fiexed coordinates axis + // rotated to the earth fixed coordinates axis SGVec3d off = hlTrans.backTransform(_off); // Add the position offset of the AIModel to gain the earth centered position @@ -487,9 +611,9 @@ SGVec3d FGAIBase::getCartPos() const { } bool FGAIBase::getGroundElevationM(const SGGeod& pos, double& elev, - const SGMaterial** material) const { + const simgear::BVHMaterial** material) const { return globals->get_scenery()->get_elevation_m(pos, elev, material, - model.get()); + _model.get()); } double FGAIBase::_getCartPosX() const { @@ -525,6 +649,52 @@ void FGAIBase::_setSubID( int s ) { _subID = s; } +bool FGAIBase::setParentNode() { + + if (_parent == ""){ + SG_LOG(SG_AI, SG_ALERT, "AIBase: " << _name + << " parent not set "); + return false; + } + + const SGPropertyNode_ptr ai = fgGetNode("/ai/models", true); + + for (int i = ai->nChildren() - 1; i >= -1; i--) { + SGPropertyNode_ptr model; + + if (i < 0) { // last iteration: selected model + model = _selected_ac; + } else { + model = ai->getChild(i); + string path = ai->getPath(); + const string name = model->getStringValue("name"); + + if (!model->nChildren()){ + continue; + } + if (name == _parent) { + _selected_ac = model; // save selected model for last iteration + break; + } + + } + if (!model) + continue; + + }// end for loop + + if (_selected_ac != 0){ + const string name = _selected_ac->getStringValue("name"); + return true; + } else { + SG_LOG(SG_AI, SG_ALERT, "AIBase: " << _name + << " parent not found: dying "); + setDie(true); + return false; + } + +} + double FGAIBase::_getLongitude() const { return pos.getLongitudeDeg(); } @@ -533,7 +703,7 @@ double FGAIBase::_getLatitude() const { return pos.getLatitudeDeg(); } -double FGAIBase::_getElevationFt () const { +double FGAIBase::_getElevationFt() const { return pos.getElevationFt(); } @@ -542,7 +712,7 @@ double FGAIBase::_getRdot() const { } double FGAIBase::_getVS_fps() const { - return vs*60.0; + return vs/60.0; } double FGAIBase::_get_speed_east_fps() const { @@ -554,13 +724,19 @@ double FGAIBase::_get_speed_north_fps() const { } void FGAIBase::_setVS_fps( double _vs ) { - vs = _vs/60.0; + vs = _vs*60.0; } double FGAIBase::_getAltitude() const { return altitude_ft; } +double FGAIBase::_getAltitudeAGL(SGGeod inpos, double start){ + getGroundElevationM(SGGeod::fromGeodM(inpos, start), + _elevation_m, NULL); + return inpos.getElevationFt() - _elevation_m * SG_METER_TO_FEET; +} + bool FGAIBase::_getServiceable() const { return serviceable; } @@ -714,3 +890,28 @@ int FGAIBase::_newAIModelID() { return id; } + +FGAIModelData::FGAIModelData(SGPropertyNode *root) + : _nasal( new FGNasalModelDataProxy(root) ), + _ready(false), + _initialized(false) +{ +} + +FGAIModelData::~FGAIModelData() +{ + delete _nasal; + _nasal = NULL; +} + +void FGAIModelData::modelLoaded(const string& path, SGPropertyNode *prop, osg::Node *n) +{ + // WARNING: Called in a separate OSG thread! Only use thread-safe stuff here... + if (_ready) + return; + + _fxpath = prop->getStringValue("sound/path"); + _nasal->modelLoaded(path, prop, n); + + _ready = true; +}