This commit is contained in:
gallaert
2018-08-29 21:01:36 +01:00
18 changed files with 290 additions and 57 deletions

View File

@@ -202,11 +202,8 @@ if (MSVC AND MSVC_3RDPARTY_ROOT)
message(STATUS "BOOST_INCLUDEDIR is ${BOOST_INCLUDEDIR}")
endif()
if (NOT USE_AEONWAVE)
set (OPENAL_INCLUDE_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/include)
set (OPENAL_LIBRARY_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/lib)
message(STATUS "OPENAL_INCLUDE_DIR is ${OPENAL_INCLUDE_DIR}")
endif()
set (OPENAL_INCLUDE_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/include)
set (OPENAL_LIBRARY_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/lib)
endif (MSVC AND MSVC_3RDPARTY_ROOT)
if(APPLE)

View File

@@ -97,17 +97,26 @@ namespace canvas
|| (!geo_node->isDirty() && !_projection_dirty) )
continue;
GeoCoord lat = parseGeoCoord(geo_node->getLat());
if( lat.type != GeoCoord::LATITUDE )
continue;
GeoCoord lon = parseGeoCoord(geo_node->getLon());
if( lon.type != GeoCoord::LONGITUDE )
continue;
Projection::ScreenPosition pos =
_projection->worldToScreen(lat.value, lon.value);
double latD = -9999.0, lonD = -9999.0;
if (geo_node->isDirty()) {
GeoCoord lat = parseGeoCoord(geo_node->getLat());
if( lat.type != GeoCoord::LATITUDE )
continue;
GeoCoord lon = parseGeoCoord(geo_node->getLon());
if( lon.type != GeoCoord::LONGITUDE )
continue;
// 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->print();

View File

@@ -863,6 +863,9 @@ namespace canvas
//----------------------------------------------------------------------------
void Path::childChanged(SGPropertyNode* child)
{
if( child->getParent() != _node )
return;
const std::string& name = child->getNameString();
const std::string &prName = child->getParent()->getNameString();
@@ -892,9 +895,6 @@ namespace canvas
return;
}
if( child->getParent() != _node )
return;
if( name == "cmd" )
_attributes_dirty |= CMDS;
else if( name == "coord" )

View File

@@ -67,7 +67,8 @@ namespace canvas
{
_node_lat = node;
_status &= ~LAT_MISSING;
_xNode.reset();
if( node == _node_lon )
{
_node_lon = 0;
@@ -79,7 +80,8 @@ namespace canvas
{
_node_lon = node;
_status &= ~LON_MISSING;
_yNode.reset();
if( node == _node_lat )
{
_node_lat = 0;
@@ -97,19 +99,34 @@ namespace canvas
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)
{
_target_name = name;
_xNode.reset();
_yNode.reset();
}
void setScreenPos(float x, float y)
{
assert( isComplete() );
SGPropertyNode *parent = _node_lat->getParent();
parent->getChild(_target_name, _node_lat->getIndex(), true)
->setDoubleValue(x);
parent->getChild(_target_name, _node_lon->getIndex(), true)
->setDoubleValue(y);
if (!_xNode) {
SGPropertyNode *parent = _node_lat->getParent();
_xNode = parent->getChild(_target_name, _node_lat->getIndex(), true);
}
if (!_yNode) {
SGPropertyNode *parent = _node_lat->getParent();
_yNode = parent->getChild(_target_name, _node_lon->getIndex(), true);
}
_xNode->setDoubleValue(x);
_yNode->setDoubleValue(y);
}
void print()
@@ -125,6 +142,9 @@ namespace canvas
SGPropertyNode *_node_lat,
*_node_lon;
std::string _target_name;
SGPropertyNode_ptr _xNode,
_yNode;
std::pair<double, double> _cachedLatLon;
};

View File

@@ -1,7 +1,7 @@
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)
simgear_component(debug debug "${SOURCES}" "${HEADERS}")
simgear_component(debug debug "${SOURCES}" "${HEADERS}")

View File

@@ -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;
}
}
};

View File

@@ -34,7 +34,8 @@ typedef enum {
SG_GUI = 0x00800000,
SG_TERRASYNC = 0x01000000,
SG_PARTICLES = 0x02000000,
SG_UNDEFD = 0x04000000, // For range checking
SG_HEADLESS = 0x04000000,
SG_UNDEFD = 0x08000000, // For range checking
SG_ALL = 0xFFFFFFFF
} sgDebugClass;

View File

@@ -100,6 +100,7 @@ const char* LogCallback::debugClassToString(sgDebugClass c)
case SG_GUI: return "gui";
case SG_TERRASYNC: return "terrasync";
case SG_PARTICLES: return "particles";
case SG_HEADLESS: return "headless";
default: return "unknown";
}
}

View File

@@ -1006,11 +1006,11 @@ HTTPRepository::failure() const
SGPath cachePath = basePath;
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;
for (it = hashes.begin(); it != hashes.end(); ++it) {
stream << it->filePath << ":" << it->modTime << ":"
<< it->lengthBytes << ":" << it->hashHex << "\n";
stream << it->filePath << "*" << it->modTime << "*"
<< it->lengthBytes << "*" << it->hashHex << "\n";
}
stream.close();
hashCacheDirty = false;
@@ -1034,7 +1034,7 @@ HTTPRepository::failure() const
if( line.empty() || line[0] == '#' )
continue;
string_list tokens = simgear::strutils::split( line, ":" );
string_list tokens = simgear::strutils::split(line, "*");
if( tokens.size() < 4 ) {
SG_LOG(SG_TERRASYNC, SG_WARN, "invalid entry in '" << cachePath << "': '" << line << "' (ignoring line)");
continue;
@@ -1056,6 +1056,9 @@ HTTPRepository::failure() const
entry.lengthBytes = strtol(sizeData.c_str(), NULL, 10);
hashes.push_back(entry);
}
SG_LOG(SG_TERRASYNC, SG_INFO, "restored hashes:" << hashes.size());
}
class DirectoryWithPath

View File

@@ -1379,6 +1379,35 @@ std::string formatLatLonValueAsString(double deg, LatLonFormat format,
case LatLonFormat::DECIMAL_DEGREES_SYMBOL:
::snprintf(buf, sizeof(buf), "%3.6f%s%c", deg, degSym, c);
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);
@@ -1390,6 +1419,12 @@ std::string formatGeodAsString(const SGGeod& geod, LatLonFormat format,
const char ns = (geod.getLatitudeDeg() > 0.0) ? 'N' : 'S';
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) + ","
+ formatLatLonValueAsString(geod.getLongitudeDeg(), format, ew, degreeSymbol);
}

View File

@@ -396,7 +396,8 @@ namespace simgear {
ZERO_PAD_DEGREES_MINUTES,
ZERO_PAD_DEGREES_MINUTES_SECONDS,
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

View File

@@ -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::DEGREES_MINUTES_SECONDS),
"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,
strutils::LatLonFormat::ZERO_PAD_DEGREES_MINUTES,
@@ -696,6 +704,8 @@ void test_formatGeod()
strutils::LatLonFormat::DECIMAL_DEGREES_SYMBOL,
strutils::DegreeSymbol::UTF8_DEGREE);
SG_CHECK_EQUAL(s2, "6.156800\xC2\xB0S,106.827800\xC2\xB0" "E");
}
int main(int argc, char* argv[])

View File

@@ -45,8 +45,7 @@ class Install::PackageArchiveDownloader : public HTTP::Request
public:
PackageArchiveDownloader(InstallRef aOwner) :
HTTP::Request("" /* dummy URL */),
m_owner(aOwner),
m_downloaded(0)
m_owner(aOwner)
{
m_urls = m_owner->package()->downloadUrls();
if (m_urls.empty()) {
@@ -115,6 +114,7 @@ protected:
{
const uint8_t* ubytes = (uint8_t*) s;
SG_MD5Update(&m_md5, ubytes, n);
m_downloaded += n;
m_owner->installProgress(m_downloaded, responseLength());
m_extractor->extractBytes(ubytes, n);
}
@@ -221,7 +221,7 @@ private:
string_list m_urls;
SG_MD5_CTX m_md5;
SGPath m_extractPath;
size_t m_downloaded;
size_t m_downloaded = 0;
std::unique_ptr<ArchiveExtractor> m_extractor;
};

View File

@@ -751,7 +751,7 @@ typedef SGSharedPtr<const SGPropertyNode> SGConstPropertyNode_ptr;
namespace simgear
{
typedef std::vector<SGPropertyNode_ptr> PropertyList;
using PropertyList = std::vector<SGPropertyNode_ptr>;
}
/**

View File

@@ -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
*
* Forward declarations for properties (and related structures)
@@ -7,12 +24,18 @@
#define SG_PROPS_FWD_HXX
#include <simgear/structure/SGSharedPtr.hxx>
#include <vector>
class SGPropertyNode;
typedef SGSharedPtr<SGPropertyNode> SGPropertyNode_ptr;
typedef SGSharedPtr<const SGPropertyNode> SGConstPropertyNode_ptr;
namespace simgear
{
using PropertyList = std::vector<SGPropertyNode_ptr>;
}
class SGCondition;
#endif // of SG_PROPS_FWD_HXX

View File

@@ -440,6 +440,8 @@ SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
if (name.empty()) {
SG_LOG(SG_GENERAL, SG_DEV_WARN, "adding subsystem to group without a name");
// TODO, make this an exception in the future
} else if (subsystem->name().empty()) {
subsystem->set_name(name);
} else if (name != subsystem->name()) {
SG_LOG(SG_GENERAL, SG_DEV_WARN, "adding subsystem to group with name '" << name
<< "', but name() returns '" << subsystem->name() << "'");
@@ -453,14 +455,25 @@ SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
subsystem->set_group(this);
notifyDidChange(subsystem, State::ADD);
if (_state != State::INVALID) {
SG_LOG(SG_GENERAL, SG_DEV_WARN, "TODO: implement SGSubsystemGroup transition when adding after init");
if (_state != State::INVALID && (_state <= State::POSTINIT)) {
// 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) {
// transition out correctly
SG_LOG(SG_GENERAL, SG_DEV_WARN, "TODO: implement SGSubsystemGroup transition when removing before shutdown");
// shutdown
if ((_state >= State::INIT) && (_state < State::SHUTDOWN)) {
notifyWillChange(sub, State::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);
@@ -1150,10 +1169,9 @@ namespace {
group,
minTime);
if (arg->getBoolValue("do-bind-init", false)) {
sub->bind();
sub->init();
}
// we no longer check for the do-bind-init flag here, since set_subsystem
// tracks the group state and will transition the added subsystem
// automatically
return true;
}
@@ -1168,11 +1186,7 @@ namespace {
SG_LOG(SG_GENERAL, SG_ALERT, "do_remove_subsystem: unknown subsytem:" << name);
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!)
manager->remove(name.c_str());
return true;

View File

@@ -301,6 +301,10 @@ public:
/// get the parent group of this subsystem
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 {
INVALID = -1,
ADD = 0,
@@ -310,8 +314,8 @@ public:
REINIT,
SUSPEND,
RESUME,
UNBIND,
SHUTDOWN,
UNBIND,
REMOVE
};

View File

@@ -439,6 +439,75 @@ void testPropertyRoot()
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();
testSuspendResume();
testPropertyRoot();
testAddRemoveAfterInit();
cout << __FILE__ << ": All tests passed" << endl;
return EXIT_SUCCESS;