Merge branch 'next' of https://git.code.sf.net/p/flightgear/simgear into next
This commit is contained in:
+2
-5
@@ -202,11 +202,8 @@ if (MSVC AND MSVC_3RDPARTY_ROOT)
|
|||||||
message(STATUS "BOOST_INCLUDEDIR is ${BOOST_INCLUDEDIR}")
|
message(STATUS "BOOST_INCLUDEDIR is ${BOOST_INCLUDEDIR}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT USE_AEONWAVE)
|
set (OPENAL_INCLUDE_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/include)
|
||||||
set (OPENAL_INCLUDE_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/include)
|
set (OPENAL_LIBRARY_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/lib)
|
||||||
set (OPENAL_LIBRARY_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/lib)
|
|
||||||
message(STATUS "OPENAL_INCLUDE_DIR is ${OPENAL_INCLUDE_DIR}")
|
|
||||||
endif()
|
|
||||||
endif (MSVC AND MSVC_3RDPARTY_ROOT)
|
endif (MSVC AND MSVC_3RDPARTY_ROOT)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
|
|||||||
@@ -97,17 +97,26 @@ namespace canvas
|
|||||||
|| (!geo_node->isDirty() && !_projection_dirty) )
|
|| (!geo_node->isDirty() && !_projection_dirty) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
GeoCoord lat = parseGeoCoord(geo_node->getLat());
|
double latD = -9999.0, lonD = -9999.0;
|
||||||
if( lat.type != GeoCoord::LATITUDE )
|
if (geo_node->isDirty()) {
|
||||||
continue;
|
GeoCoord lat = parseGeoCoord(geo_node->getLat());
|
||||||
|
if( lat.type != GeoCoord::LATITUDE )
|
||||||
GeoCoord lon = parseGeoCoord(geo_node->getLon());
|
continue;
|
||||||
if( lon.type != GeoCoord::LONGITUDE )
|
|
||||||
continue;
|
GeoCoord lon = parseGeoCoord(geo_node->getLon());
|
||||||
|
if( lon.type != GeoCoord::LONGITUDE )
|
||||||
Projection::ScreenPosition pos =
|
continue;
|
||||||
_projection->worldToScreen(lat.value, lon.value);
|
|
||||||
|
// save the parsed values so we can re-use them if only projection
|
||||||
|
// is changed (very common case for moving vehicle)
|
||||||
|
latD = lat.value;
|
||||||
|
lonD = lon.value;
|
||||||
|
geo_node->setCachedLatLon(std::make_pair(latD, lonD));
|
||||||
|
} else {
|
||||||
|
std::tie(latD, lonD) = geo_node->getCachedLatLon();
|
||||||
|
}
|
||||||
|
|
||||||
|
Projection::ScreenPosition pos = _projection->worldToScreen(latD, lonD);
|
||||||
geo_node->setScreenPos(pos.x, pos.y);
|
geo_node->setScreenPos(pos.x, pos.y);
|
||||||
|
|
||||||
// geo_node->print();
|
// geo_node->print();
|
||||||
|
|||||||
@@ -863,6 +863,9 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Path::childChanged(SGPropertyNode* child)
|
void Path::childChanged(SGPropertyNode* child)
|
||||||
{
|
{
|
||||||
|
if( child->getParent() != _node )
|
||||||
|
return;
|
||||||
|
|
||||||
const std::string& name = child->getNameString();
|
const std::string& name = child->getNameString();
|
||||||
const std::string &prName = child->getParent()->getNameString();
|
const std::string &prName = child->getParent()->getNameString();
|
||||||
|
|
||||||
@@ -892,9 +895,6 @@ namespace canvas
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( child->getParent() != _node )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( name == "cmd" )
|
if( name == "cmd" )
|
||||||
_attributes_dirty |= CMDS;
|
_attributes_dirty |= CMDS;
|
||||||
else if( name == "coord" )
|
else if( name == "coord" )
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ namespace canvas
|
|||||||
{
|
{
|
||||||
_node_lat = node;
|
_node_lat = node;
|
||||||
_status &= ~LAT_MISSING;
|
_status &= ~LAT_MISSING;
|
||||||
|
_xNode.reset();
|
||||||
|
|
||||||
if( node == _node_lon )
|
if( node == _node_lon )
|
||||||
{
|
{
|
||||||
_node_lon = 0;
|
_node_lon = 0;
|
||||||
@@ -79,7 +80,8 @@ namespace canvas
|
|||||||
{
|
{
|
||||||
_node_lon = node;
|
_node_lon = node;
|
||||||
_status &= ~LON_MISSING;
|
_status &= ~LON_MISSING;
|
||||||
|
_yNode.reset();
|
||||||
|
|
||||||
if( node == _node_lat )
|
if( node == _node_lat )
|
||||||
{
|
{
|
||||||
_node_lat = 0;
|
_node_lat = 0;
|
||||||
@@ -97,19 +99,34 @@ namespace canvas
|
|||||||
return _node_lon ? _node_lon->getStringValue() : "";
|
return _node_lon ? _node_lon->getStringValue() : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setCachedLatLon(const std::pair<double, double>& latLon)
|
||||||
|
{ _cachedLatLon = latLon; }
|
||||||
|
|
||||||
|
std::pair<double, double> getCachedLatLon()
|
||||||
|
{ return _cachedLatLon; }
|
||||||
|
|
||||||
void setTargetName(const std::string& name)
|
void setTargetName(const std::string& name)
|
||||||
{
|
{
|
||||||
_target_name = name;
|
_target_name = name;
|
||||||
|
_xNode.reset();
|
||||||
|
_yNode.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setScreenPos(float x, float y)
|
void setScreenPos(float x, float y)
|
||||||
{
|
{
|
||||||
assert( isComplete() );
|
assert( isComplete() );
|
||||||
SGPropertyNode *parent = _node_lat->getParent();
|
if (!_xNode) {
|
||||||
parent->getChild(_target_name, _node_lat->getIndex(), true)
|
SGPropertyNode *parent = _node_lat->getParent();
|
||||||
->setDoubleValue(x);
|
_xNode = parent->getChild(_target_name, _node_lat->getIndex(), true);
|
||||||
parent->getChild(_target_name, _node_lon->getIndex(), true)
|
}
|
||||||
->setDoubleValue(y);
|
|
||||||
|
if (!_yNode) {
|
||||||
|
SGPropertyNode *parent = _node_lat->getParent();
|
||||||
|
_yNode = parent->getChild(_target_name, _node_lon->getIndex(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
_xNode->setDoubleValue(x);
|
||||||
|
_yNode->setDoubleValue(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print()
|
void print()
|
||||||
@@ -125,6 +142,9 @@ namespace canvas
|
|||||||
SGPropertyNode *_node_lat,
|
SGPropertyNode *_node_lat,
|
||||||
*_node_lon;
|
*_node_lon;
|
||||||
std::string _target_name;
|
std::string _target_name;
|
||||||
|
SGPropertyNode_ptr _xNode,
|
||||||
|
_yNode;
|
||||||
|
std::pair<double, double> _cachedLatLon;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
include (SimGearComponent)
|
include (SimGearComponent)
|
||||||
|
|
||||||
set(HEADERS debug_types.h logstream.hxx BufferedLogCallback.hxx)
|
set(HEADERS debug_types.h logstream.hxx BufferedLogCallback.hxx OsgIoCapture.hxx)
|
||||||
set(SOURCES logstream.cxx BufferedLogCallback.cxx)
|
set(SOURCES logstream.cxx BufferedLogCallback.cxx)
|
||||||
|
|
||||||
simgear_component(debug debug "${SOURCES}" "${HEADERS}")
|
simgear_component(debug debug "${SOURCES}" "${HEADERS}")
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <osg/Notify>
|
||||||
|
|
||||||
|
using namespace osg;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* merge OSG output into our logging system, so it gets recorded to file,
|
||||||
|
* and so we can display a GUI console with renderer issues, especially
|
||||||
|
* shader compilation warnings and errors.
|
||||||
|
*/
|
||||||
|
class NotifyLogger : public osg::NotifyHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// note this callback will be invoked by OSG from multiple threads.
|
||||||
|
// fortunately our Simgear logging implementation already handles
|
||||||
|
// that internally, so we simply pass the message on.
|
||||||
|
virtual void notify(osg::NotifySeverity severity, const char* message) {
|
||||||
|
// Detect whether a osg::Reference derived object is deleted with a non-zero
|
||||||
|
// reference count. In this case trigger a segfault to get a stack trace.
|
||||||
|
if (strstr(message, "the final reference count was")) {
|
||||||
|
// as this is going to segfault ignore the translation of severity and always output the message.
|
||||||
|
SG_LOG(SG_GL, SG_ALERT, message);
|
||||||
|
int* trigger_segfault = 0;
|
||||||
|
*trigger_segfault = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SG_LOG(SG_GL, translateSeverity(severity), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
sgDebugPriority translateSeverity(osg::NotifySeverity severity) {
|
||||||
|
switch (severity) {
|
||||||
|
case osg::ALWAYS:
|
||||||
|
case osg::FATAL: return SG_ALERT;
|
||||||
|
case osg::WARN: return SG_WARN;
|
||||||
|
case osg::NOTICE:
|
||||||
|
case osg::INFO: return SG_INFO;
|
||||||
|
case osg::DEBUG_FP:
|
||||||
|
case osg::DEBUG_INFO: return SG_DEBUG;
|
||||||
|
default: return SG_ALERT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -34,7 +34,8 @@ typedef enum {
|
|||||||
SG_GUI = 0x00800000,
|
SG_GUI = 0x00800000,
|
||||||
SG_TERRASYNC = 0x01000000,
|
SG_TERRASYNC = 0x01000000,
|
||||||
SG_PARTICLES = 0x02000000,
|
SG_PARTICLES = 0x02000000,
|
||||||
SG_UNDEFD = 0x04000000, // For range checking
|
SG_HEADLESS = 0x04000000,
|
||||||
|
SG_UNDEFD = 0x08000000, // For range checking
|
||||||
|
|
||||||
SG_ALL = 0xFFFFFFFF
|
SG_ALL = 0xFFFFFFFF
|
||||||
} sgDebugClass;
|
} sgDebugClass;
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ const char* LogCallback::debugClassToString(sgDebugClass c)
|
|||||||
case SG_GUI: return "gui";
|
case SG_GUI: return "gui";
|
||||||
case SG_TERRASYNC: return "terrasync";
|
case SG_TERRASYNC: return "terrasync";
|
||||||
case SG_PARTICLES: return "particles";
|
case SG_PARTICLES: return "particles";
|
||||||
|
case SG_HEADLESS: return "headless";
|
||||||
default: return "unknown";
|
default: return "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1006,11 +1006,11 @@ HTTPRepository::failure() const
|
|||||||
|
|
||||||
SGPath cachePath = basePath;
|
SGPath cachePath = basePath;
|
||||||
cachePath.append(".hashes");
|
cachePath.append(".hashes");
|
||||||
sg_ofstream stream(cachePath, std::ios::out | std::ios::trunc);
|
sg_ofstream stream(cachePath, std::ios::out | std::ios::trunc | std::ios::binary);
|
||||||
HashCache::const_iterator it;
|
HashCache::const_iterator it;
|
||||||
for (it = hashes.begin(); it != hashes.end(); ++it) {
|
for (it = hashes.begin(); it != hashes.end(); ++it) {
|
||||||
stream << it->filePath << ":" << it->modTime << ":"
|
stream << it->filePath << "*" << it->modTime << "*"
|
||||||
<< it->lengthBytes << ":" << it->hashHex << "\n";
|
<< it->lengthBytes << "*" << it->hashHex << "\n";
|
||||||
}
|
}
|
||||||
stream.close();
|
stream.close();
|
||||||
hashCacheDirty = false;
|
hashCacheDirty = false;
|
||||||
@@ -1034,7 +1034,7 @@ HTTPRepository::failure() const
|
|||||||
if( line.empty() || line[0] == '#' )
|
if( line.empty() || line[0] == '#' )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
string_list tokens = simgear::strutils::split( line, ":" );
|
string_list tokens = simgear::strutils::split(line, "*");
|
||||||
if( tokens.size() < 4 ) {
|
if( tokens.size() < 4 ) {
|
||||||
SG_LOG(SG_TERRASYNC, SG_WARN, "invalid entry in '" << cachePath << "': '" << line << "' (ignoring line)");
|
SG_LOG(SG_TERRASYNC, SG_WARN, "invalid entry in '" << cachePath << "': '" << line << "' (ignoring line)");
|
||||||
continue;
|
continue;
|
||||||
@@ -1056,6 +1056,9 @@ HTTPRepository::failure() const
|
|||||||
entry.lengthBytes = strtol(sizeData.c_str(), NULL, 10);
|
entry.lengthBytes = strtol(sizeData.c_str(), NULL, 10);
|
||||||
hashes.push_back(entry);
|
hashes.push_back(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SG_LOG(SG_TERRASYNC, SG_INFO, "restored hashes:" << hashes.size());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DirectoryWithPath
|
class DirectoryWithPath
|
||||||
|
|||||||
@@ -1379,6 +1379,35 @@ std::string formatLatLonValueAsString(double deg, LatLonFormat format,
|
|||||||
case LatLonFormat::DECIMAL_DEGREES_SYMBOL:
|
case LatLonFormat::DECIMAL_DEGREES_SYMBOL:
|
||||||
::snprintf(buf, sizeof(buf), "%3.6f%s%c", deg, degSym, c);
|
::snprintf(buf, sizeof(buf), "%3.6f%s%c", deg, degSym, c);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case LatLonFormat::ICAO_ROUTE_DEGREES:
|
||||||
|
{
|
||||||
|
min = (deg - int(deg)) * 60.0;
|
||||||
|
if (min >= 59.9995) {
|
||||||
|
min -= 60.0;
|
||||||
|
deg += 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static_cast<int>(min) == 0) {
|
||||||
|
// 7-digit mode
|
||||||
|
if (c == 'N' || c == 'S') {
|
||||||
|
snprintf(buf, sizeof(buf), "%02d%c", int(deg), c);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, sizeof(buf), "%03d%c", int(deg), c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 11-digit mode
|
||||||
|
if (c == 'N' || c == 'S') {
|
||||||
|
snprintf(buf, sizeof(buf), "%02d%02d%c", int(deg), int(min), c);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, sizeof(buf), "%03d%02d%c", int(deg), int(min), c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::string(buf);
|
return std::string(buf);
|
||||||
@@ -1390,6 +1419,12 @@ std::string formatGeodAsString(const SGGeod& geod, LatLonFormat format,
|
|||||||
const char ns = (geod.getLatitudeDeg() > 0.0) ? 'N' : 'S';
|
const char ns = (geod.getLatitudeDeg() > 0.0) ? 'N' : 'S';
|
||||||
const char ew = (geod.getLongitudeDeg() > 0.0) ? 'E' : 'W';
|
const char ew = (geod.getLongitudeDeg() > 0.0) ? 'E' : 'W';
|
||||||
|
|
||||||
|
// no comma seperator
|
||||||
|
if (format == LatLonFormat::ICAO_ROUTE_DEGREES) {
|
||||||
|
return formatLatLonValueAsString(geod.getLatitudeDeg(), format, ns, degreeSymbol) +
|
||||||
|
formatLatLonValueAsString(geod.getLongitudeDeg(), format, ew, degreeSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
return formatLatLonValueAsString(geod.getLatitudeDeg(), format, ns, degreeSymbol) + ","
|
return formatLatLonValueAsString(geod.getLatitudeDeg(), format, ns, degreeSymbol) + ","
|
||||||
+ formatLatLonValueAsString(geod.getLongitudeDeg(), format, ew, degreeSymbol);
|
+ formatLatLonValueAsString(geod.getLongitudeDeg(), format, ew, degreeSymbol);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -396,7 +396,8 @@ namespace simgear {
|
|||||||
ZERO_PAD_DEGREES_MINUTES,
|
ZERO_PAD_DEGREES_MINUTES,
|
||||||
ZERO_PAD_DEGREES_MINUTES_SECONDS,
|
ZERO_PAD_DEGREES_MINUTES_SECONDS,
|
||||||
TRINITY_HOUSE, ///< dd* mm'.mmm X, ddd* mm'.mmm X (Trinity House Navigation standard).
|
TRINITY_HOUSE, ///< dd* mm'.mmm X, ddd* mm'.mmm X (Trinity House Navigation standard).
|
||||||
DECIMAL_DEGREES_SYMBOL ///< 88.4*N,4.54*W
|
DECIMAL_DEGREES_SYMBOL, ///< 88.4*N,4.54*W
|
||||||
|
ICAO_ROUTE_DEGREES, ///< 52N045W or 5212N04512W - precision auto-selected
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class DegreeSymbol
|
enum class DegreeSymbol
|
||||||
|
|||||||
@@ -684,6 +684,14 @@ void test_formatGeod()
|
|||||||
SG_CHECK_EQUAL(strutils::formatGeodAsString(a, strutils::LatLonFormat::SIGNED_DECIMAL_DEGREES), "55.450000,-3.460000");
|
SG_CHECK_EQUAL(strutils::formatGeodAsString(a, strutils::LatLonFormat::SIGNED_DECIMAL_DEGREES), "55.450000,-3.460000");
|
||||||
SG_CHECK_EQUAL(strutils::formatGeodAsString(a, strutils::LatLonFormat::DEGREES_MINUTES_SECONDS),
|
SG_CHECK_EQUAL(strutils::formatGeodAsString(a, strutils::LatLonFormat::DEGREES_MINUTES_SECONDS),
|
||||||
"55*27'00.0\"N,3*27'36.0\"W");
|
"55*27'00.0\"N,3*27'36.0\"W");
|
||||||
|
|
||||||
|
|
||||||
|
SG_CHECK_EQUAL(strutils::formatGeodAsString(a, strutils::LatLonFormat::ICAO_ROUTE_DEGREES),
|
||||||
|
"5527N00327W");
|
||||||
|
SGGeod shortA = SGGeod::fromDeg(106, -34);
|
||||||
|
SG_CHECK_EQUAL(strutils::formatGeodAsString(shortA, strutils::LatLonFormat::ICAO_ROUTE_DEGREES),
|
||||||
|
"34S106E");
|
||||||
|
|
||||||
|
|
||||||
const auto s = strutils::formatGeodAsString(a,
|
const auto s = strutils::formatGeodAsString(a,
|
||||||
strutils::LatLonFormat::ZERO_PAD_DEGREES_MINUTES,
|
strutils::LatLonFormat::ZERO_PAD_DEGREES_MINUTES,
|
||||||
@@ -696,6 +704,8 @@ void test_formatGeod()
|
|||||||
strutils::LatLonFormat::DECIMAL_DEGREES_SYMBOL,
|
strutils::LatLonFormat::DECIMAL_DEGREES_SYMBOL,
|
||||||
strutils::DegreeSymbol::UTF8_DEGREE);
|
strutils::DegreeSymbol::UTF8_DEGREE);
|
||||||
SG_CHECK_EQUAL(s2, "6.156800\xC2\xB0S,106.827800\xC2\xB0" "E");
|
SG_CHECK_EQUAL(s2, "6.156800\xC2\xB0S,106.827800\xC2\xB0" "E");
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
|
|||||||
@@ -45,8 +45,7 @@ class Install::PackageArchiveDownloader : public HTTP::Request
|
|||||||
public:
|
public:
|
||||||
PackageArchiveDownloader(InstallRef aOwner) :
|
PackageArchiveDownloader(InstallRef aOwner) :
|
||||||
HTTP::Request("" /* dummy URL */),
|
HTTP::Request("" /* dummy URL */),
|
||||||
m_owner(aOwner),
|
m_owner(aOwner)
|
||||||
m_downloaded(0)
|
|
||||||
{
|
{
|
||||||
m_urls = m_owner->package()->downloadUrls();
|
m_urls = m_owner->package()->downloadUrls();
|
||||||
if (m_urls.empty()) {
|
if (m_urls.empty()) {
|
||||||
@@ -115,6 +114,7 @@ protected:
|
|||||||
{
|
{
|
||||||
const uint8_t* ubytes = (uint8_t*) s;
|
const uint8_t* ubytes = (uint8_t*) s;
|
||||||
SG_MD5Update(&m_md5, ubytes, n);
|
SG_MD5Update(&m_md5, ubytes, n);
|
||||||
|
m_downloaded += n;
|
||||||
m_owner->installProgress(m_downloaded, responseLength());
|
m_owner->installProgress(m_downloaded, responseLength());
|
||||||
m_extractor->extractBytes(ubytes, n);
|
m_extractor->extractBytes(ubytes, n);
|
||||||
}
|
}
|
||||||
@@ -221,7 +221,7 @@ private:
|
|||||||
string_list m_urls;
|
string_list m_urls;
|
||||||
SG_MD5_CTX m_md5;
|
SG_MD5_CTX m_md5;
|
||||||
SGPath m_extractPath;
|
SGPath m_extractPath;
|
||||||
size_t m_downloaded;
|
size_t m_downloaded = 0;
|
||||||
std::unique_ptr<ArchiveExtractor> m_extractor;
|
std::unique_ptr<ArchiveExtractor> m_extractor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -751,7 +751,7 @@ typedef SGSharedPtr<const SGPropertyNode> SGConstPropertyNode_ptr;
|
|||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
typedef std::vector<SGPropertyNode_ptr> PropertyList;
|
using PropertyList = std::vector<SGPropertyNode_ptr>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,3 +1,20 @@
|
|||||||
|
// Copyright (C) 2018 James Turner - <james@flightgear>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library 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
|
||||||
|
// Library 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.
|
||||||
|
//
|
||||||
|
|
||||||
/** \file
|
/** \file
|
||||||
*
|
*
|
||||||
* Forward declarations for properties (and related structures)
|
* Forward declarations for properties (and related structures)
|
||||||
@@ -7,12 +24,18 @@
|
|||||||
#define SG_PROPS_FWD_HXX
|
#define SG_PROPS_FWD_HXX
|
||||||
|
|
||||||
#include <simgear/structure/SGSharedPtr.hxx>
|
#include <simgear/structure/SGSharedPtr.hxx>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class SGPropertyNode;
|
class SGPropertyNode;
|
||||||
|
|
||||||
typedef SGSharedPtr<SGPropertyNode> SGPropertyNode_ptr;
|
typedef SGSharedPtr<SGPropertyNode> SGPropertyNode_ptr;
|
||||||
typedef SGSharedPtr<const SGPropertyNode> SGConstPropertyNode_ptr;
|
typedef SGSharedPtr<const SGPropertyNode> SGConstPropertyNode_ptr;
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
using PropertyList = std::vector<SGPropertyNode_ptr>;
|
||||||
|
}
|
||||||
|
|
||||||
class SGCondition;
|
class SGCondition;
|
||||||
|
|
||||||
#endif // of SG_PROPS_FWD_HXX
|
#endif // of SG_PROPS_FWD_HXX
|
||||||
|
|||||||
@@ -440,6 +440,8 @@ SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
|
|||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
SG_LOG(SG_GENERAL, SG_DEV_WARN, "adding subsystem to group without a name");
|
SG_LOG(SG_GENERAL, SG_DEV_WARN, "adding subsystem to group without a name");
|
||||||
// TODO, make this an exception in the future
|
// TODO, make this an exception in the future
|
||||||
|
} else if (subsystem->name().empty()) {
|
||||||
|
subsystem->set_name(name);
|
||||||
} else if (name != subsystem->name()) {
|
} else if (name != subsystem->name()) {
|
||||||
SG_LOG(SG_GENERAL, SG_DEV_WARN, "adding subsystem to group with name '" << name
|
SG_LOG(SG_GENERAL, SG_DEV_WARN, "adding subsystem to group with name '" << name
|
||||||
<< "', but name() returns '" << subsystem->name() << "'");
|
<< "', but name() returns '" << subsystem->name() << "'");
|
||||||
@@ -453,14 +455,25 @@ SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
|
|||||||
subsystem->set_group(this);
|
subsystem->set_group(this);
|
||||||
notifyDidChange(subsystem, State::ADD);
|
notifyDidChange(subsystem, State::ADD);
|
||||||
|
|
||||||
if (_state != State::INVALID) {
|
if (_state != State::INVALID && (_state <= State::POSTINIT)) {
|
||||||
SG_LOG(SG_GENERAL, SG_DEV_WARN, "TODO: implement SGSubsystemGroup transition when adding after init");
|
|
||||||
// transition to the correct state
|
// transition to the correct state
|
||||||
// bind
|
if (_state >= State::BIND) {
|
||||||
|
notifyWillChange(subsystem, State::BIND);
|
||||||
|
subsystem->bind();
|
||||||
|
notifyDidChange(subsystem, State::BIND);
|
||||||
|
}
|
||||||
|
|
||||||
// init
|
if (_state >= State::INIT) {
|
||||||
|
notifyWillChange(subsystem, State::INIT);
|
||||||
|
subsystem->init();
|
||||||
|
notifyDidChange(subsystem, State::INIT);
|
||||||
|
}
|
||||||
|
|
||||||
// post-init
|
if (_state == State::POSTINIT) {
|
||||||
|
notifyWillChange(subsystem, State::POSTINIT);
|
||||||
|
subsystem->postinit();
|
||||||
|
notifyDidChange(subsystem, State::POSTINIT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -502,11 +515,17 @@ SGSubsystemGroup::remove_subsystem(const string &name)
|
|||||||
|
|
||||||
if (_state != State::INVALID) {
|
if (_state != State::INVALID) {
|
||||||
// transition out correctly
|
// transition out correctly
|
||||||
SG_LOG(SG_GENERAL, SG_DEV_WARN, "TODO: implement SGSubsystemGroup transition when removing before shutdown");
|
if ((_state >= State::INIT) && (_state < State::SHUTDOWN)) {
|
||||||
|
notifyWillChange(sub, State::SHUTDOWN);
|
||||||
// shutdown
|
sub->shutdown();
|
||||||
|
notifyDidChange(sub, State::SHUTDOWN);
|
||||||
|
}
|
||||||
|
|
||||||
// unbind
|
if ((_state >= State::BIND) && (_state < State::UNBIND)) {
|
||||||
|
notifyWillChange(sub, State::UNBIND);
|
||||||
|
sub->unbind();
|
||||||
|
notifyDidChange(sub, State::UNBIND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyWillChange(sub, State::REMOVE);
|
notifyWillChange(sub, State::REMOVE);
|
||||||
@@ -1150,10 +1169,9 @@ namespace {
|
|||||||
group,
|
group,
|
||||||
minTime);
|
minTime);
|
||||||
|
|
||||||
if (arg->getBoolValue("do-bind-init", false)) {
|
// we no longer check for the do-bind-init flag here, since set_subsystem
|
||||||
sub->bind();
|
// tracks the group state and will transition the added subsystem
|
||||||
sub->init();
|
// automatically
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1168,11 +1186,7 @@ namespace {
|
|||||||
SG_LOG(SG_GENERAL, SG_ALERT, "do_remove_subsystem: unknown subsytem:" << name);
|
SG_LOG(SG_GENERAL, SG_ALERT, "do_remove_subsystem: unknown subsytem:" << name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// is it safe to always call these? let's assume so!
|
|
||||||
instance->shutdown();
|
|
||||||
instance->unbind();
|
|
||||||
|
|
||||||
// unplug from the manager (this also deletes the instance!)
|
// unplug from the manager (this also deletes the instance!)
|
||||||
manager->remove(name.c_str());
|
manager->remove(name.c_str());
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -301,6 +301,10 @@ public:
|
|||||||
/// get the parent group of this subsystem
|
/// get the parent group of this subsystem
|
||||||
SGSubsystemGroup* get_group() const;
|
SGSubsystemGroup* get_group() const;
|
||||||
|
|
||||||
|
// ordering here is exceptionally important, due to
|
||||||
|
// liveness of ranges. If you're extending this consider
|
||||||
|
// carefully where the new state lies and position it correctly.
|
||||||
|
// Also extend the tests to ensure you handle all cases.
|
||||||
enum class State {
|
enum class State {
|
||||||
INVALID = -1,
|
INVALID = -1,
|
||||||
ADD = 0,
|
ADD = 0,
|
||||||
@@ -310,8 +314,8 @@ public:
|
|||||||
REINIT,
|
REINIT,
|
||||||
SUSPEND,
|
SUSPEND,
|
||||||
RESUME,
|
RESUME,
|
||||||
UNBIND,
|
|
||||||
SHUTDOWN,
|
SHUTDOWN,
|
||||||
|
UNBIND,
|
||||||
REMOVE
|
REMOVE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -439,6 +439,75 @@ void testPropertyRoot()
|
|||||||
SG_CHECK_EQUAL(props->getIntValue("anothersub/bar"), 172);
|
SG_CHECK_EQUAL(props->getIntValue("anothersub/bar"), 172);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testAddRemoveAfterInit()
|
||||||
|
{
|
||||||
|
SGSharedPtr<SGSubsystemMgr> manager = new SGSubsystemMgr;
|
||||||
|
auto d = new RecorderDelegate;
|
||||||
|
manager->addDelegate(d);
|
||||||
|
|
||||||
|
auto group = manager->add<InstrumentGroup>();
|
||||||
|
SG_VERIFY(group);
|
||||||
|
|
||||||
|
auto radio1 = manager->createInstance<FakeRadioSub>("nav1");
|
||||||
|
group->set_subsystem(radio1);
|
||||||
|
|
||||||
|
auto com1 = manager->createInstance<FakeRadioSub>("com1");
|
||||||
|
group->set_subsystem(com1);
|
||||||
|
auto com2 = manager->createInstance<FakeRadioSub>("com2");
|
||||||
|
group->set_subsystem(com2);
|
||||||
|
|
||||||
|
manager->bind();
|
||||||
|
manager->init();
|
||||||
|
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-init"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.nav1-did-bind"));
|
||||||
|
|
||||||
|
auto radio2 = manager->createInstance<FakeRadioSub>("nav2");
|
||||||
|
group->set_subsystem(radio2);
|
||||||
|
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.nav2-will-init"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.nav2-did-init"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.nav2-did-bind"));
|
||||||
|
|
||||||
|
bool ok = manager->remove("fake-radio.nav1");
|
||||||
|
SG_VERIFY(ok);
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-shutdown"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.nav1-did-shutdown"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-unbind"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.nav1-did-unbind"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-remove"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.nav1-did-remove"));
|
||||||
|
|
||||||
|
manager->shutdown();
|
||||||
|
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.nav2-will-shutdown"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.nav2-did-shutdown"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.com1-will-shutdown"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.com1-did-shutdown"));
|
||||||
|
|
||||||
|
d->events.clear();
|
||||||
|
|
||||||
|
ok = manager->remove("fake-radio.com1");
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.com1-will-remove"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.com1-did-remove"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.com1-will-unbind"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.com1-did-unbind"));
|
||||||
|
SG_VERIFY(!d->hasEvent("fake-radio.com1-will-shutdown"));
|
||||||
|
SG_VERIFY(!d->hasEvent("fake-radio.com1-did-shutdown"));
|
||||||
|
|
||||||
|
manager->unbind();
|
||||||
|
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.com2-will-unbind"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.com2-did-unbind"));
|
||||||
|
|
||||||
|
d->events.clear();
|
||||||
|
manager->remove("fake-radio.com2");
|
||||||
|
SG_VERIFY(!d->hasEvent("fake-radio.com2-will-unbind"));
|
||||||
|
SG_VERIFY(!d->hasEvent("fake-radio.com2-did-unbind"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.com2-will-remove"));
|
||||||
|
SG_VERIFY(d->hasEvent("fake-radio.com2-did-remove"));
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
@@ -450,6 +519,7 @@ int main(int argc, char* argv[])
|
|||||||
testIncrementalInit();
|
testIncrementalInit();
|
||||||
testSuspendResume();
|
testSuspendResume();
|
||||||
testPropertyRoot();
|
testPropertyRoot();
|
||||||
|
testAddRemoveAfterInit();
|
||||||
|
|
||||||
cout << __FILE__ << ": All tests passed" << endl;
|
cout << __FILE__ << ": All tests passed" << endl;
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|||||||
Reference in New Issue
Block a user