Compare commits

..

33 Commits

Author SHA1 Message Date
Automatic Release Builder
ca5f66da9f new version: 2020.3.6 2021-01-20 13:01:25 +00:00
James Turner
92d053d850 Tolerate blank lines in buildings lists 2021-01-20 11:35:33 +00:00
Colin Geniet
001ae80723 Animations: Fix spin for Compositor lights
The 'spin' animation has a strange behaviour:
it pushes a temporary rotation matrix on the transformation stack during
cull traversal, and removes it thereafter.
Thus, the rotation matrix is missing outside of cull traversal, e.g.
when the position of Compositor lights is computed.

The same issue was fixed for the 'rotate' animation by commit
e202d4e4a5
(this mentions broken 'picking' animations as a different manifestation
of the same issue).

Fix this by setting the angle of the persistent SGRotateTransform,
instead of creating a temporary rotation matrix.
2021-01-15 15:45:26 +00:00
James Turner
58d9a6d0b5 Sentry: adjust reporting of missing shaders
Reduce noise on the backend when a shader is missing, by special-
casing how we report it.
2021-01-05 12:58:46 +00:00
Scott Giese
261316cb45 Support Boost v1.75
Resolved a breaking change.
2021-01-02 21:57:54 -06:00
Stuart Buchanan
2ad4d2e672 Fix hang on "Loading Scenery" over the sea
Previously attempting to start on an ocean tile with static
models present cause FG to spin on "Loading Scenery".

This was caused by not creating a BVH for an ocean tile in
the specific case where there was STG models, due to a PagedLOD
node being inserted in the scene graph.  So
FG never thought the scenery was loaded sufficient to place
the aircraft.

By explicitly creating a BVH for ocean tiles the problem is
fixed.

Candidate for 2020.X
2021-01-01 22:41:47 +00:00
James Turner
1d9fa929fa Launhcer: fix crashes adding a catalog
Traversing a container which is modified causes crashes, take a copy
during traversal for firePackageStatus.

Sentry-Id: FLIGHTGEAR-CJF
Sentry-Id: FLIGHTGEAR-CJ5
2021-01-01 22:41:42 +00:00
James Turner
26bb6236a0 Effect builder: catch allocation failures
Fail on bad_alloc of reading texture images, instead of crashing.
2020-12-28 15:08:49 +00:00
Scott Giese
b2acf5a623 fix: sky and cockpit to turn black
Metar sky condition without base layer height (e.g. FEW///) is the cause of this issue.
Randomize the base layer height when the actual height is unknown.
2020-12-26 10:53:49 -06:00
James Turner
bea88bb3a9 Fix BTG error reporting
Use gzerror, not strerror, for these codes.
2020-12-21 15:31:36 +00:00
Automatic Release Builder
def2af2bdd new version: 2020.3.5 2020-12-17 13:48:00 +00:00
Fernando García Liñán
6f6d705f22 Add support for anisotropic filtering in Canvas 2020-12-17 13:00:01 +00:00
Richard Harrison
e9c33104d3 DDS-TC add option to exclude all Canvas orignated images. 2020-12-17 12:59:26 +00:00
Richard Harrison
985897f8ba Emesary : change to use scoped lock
- scoped locks using lock_guard are better
- because of this the exception handler can also be removed;
  although this was originally intended to manage the locks
  it never did work properly with C++ exceptions.
2020-12-17 12:57:53 +00:00
Richard Harrison
4251b28e88 Emesary: add missing property initialisation to constructor 2020-12-17 12:56:49 +00:00
James Turner
76540a211c SGGeod: add static constructor of an invalid Geod
Use this to allow explicitly initializing a value which isValid
will return false for.
2020-12-17 12:55:30 +00:00
James Turner
904fc5a7dd Fix Nasal GC errors on tests/reset
Ensure the Context temps are cleared, and when recycling an naCode,
ensure old values are cleared explicily.

Sentry-Id: FLIGHTGEAR-Y
2020-12-17 12:55:25 +00:00
Stuart Buchanan
4aebc159d5 Use ref_ptr for ReaderWriterSPT 2020-12-07 17:18:32 +00:00
Richard Harrison
f89227fc1a Remove mutex lock on realizeTechniques
This was causing a deadlock - and I can't quite remember what problem it was intended to solve so it is best to remove it.
2020-12-07 17:17:44 +00:00
James Turner
f50f383cc0 Reporting of std::bad_alloc in Subsystem::update
Trying to trace down our bad-alloc exception, starting with the simplest
place for now.
2020-12-07 17:16:58 +00:00
James Turner
706ab387de Add reporting callback option to SimGear
Allows us to trigger an error logging callback explicitly, which can
be used to drive Sentry.io on the FlightGear side.
2020-12-07 17:16:47 +00:00
James Turner
cddfdb7d1d TerraSync: stronger fix for handling 0-byte files
Change logic so we create an empty file for such cases, i.e exactly
matching the repository. This simplifies logic in downstream code,
compared with not creating a local file.

Add a test-case to cover this

Modify TerraSync to detect a failure of Airports_archive downloading,
and fall back to file-by-file updating.
2020-12-07 17:15:51 +00:00
James Turner
3c64578848 HTTPRepository: don’t crash on empty files
Fix some additional crash cases around 0-length files
2020-12-07 17:15:38 +00:00
James Turner
e1fe9b45e0 Unzip: adjust error reporting mechanism
Don’t use local exception throw+catch to report failures in extracting
a zip archive, since this generates noise in Sentry.
2020-12-07 17:15:30 +00:00
James Turner
8fdc1d306f State-machines: don’t require name for transitions
Allow anonymous transitions, since the name is purely informational
(unlike for states).

Sentry-Id: FLIGHTGEAR-9H
2020-12-07 17:15:17 +00:00
Automatic Release Builder
6e0c39bb68 new version: 2020.3.4 2020-11-30 11:17:52 +00:00
Julian Smith
f20b416cfe simgear/props/props.cxx: use rmutex to protect SGPropertyNodeListeners.
Also added asserts to check _num_iterators always >= 0.
2020-11-29 20:16:46 +00:00
Scott Giese
47e06b5216 METAR: mitigate wind sensor failures 2020-11-29 16:25:01 +00:00
James Turner
bfcdf22705 TerraSync: fix crashes with null file return
Not sure how this is happening, but, check for a null file object
in FileGetRequest::onDone.
2020-11-29 16:23:44 +00:00
Stuart Buchanan
d0db407faa Set minimum expiry time on STG nodes. 2020-11-29 16:23:40 +00:00
Automatic Release Builder
d95b1c0441 new version: 2020.3.3 2020-11-12 11:14:23 +00:00
James Turner
837ba86d57 DNSClient: own requests, and cancel them on timeout
Fixes crashes where a request times-out, but then is completed by
UDN sometime afterwards, with a free-d object. Have the DNS::Client own
requests, and be able to retrieve the udns_query to cancel them, in 
the timeout case.

Fixes a couple of Sentry reports.
2020-11-12 09:39:58 +00:00
Automatic Release Builder
0cb1b463e1 Catalogs: fix ownership of new Catalogs
When doing the initial download of a Catalog, ensure we still keep
an owning ref to it.
2020-11-11 21:18:57 +00:00
37 changed files with 548 additions and 267 deletions

View File

@@ -1 +1 @@
2020.3.2
2020.3.6

View File

@@ -691,6 +691,10 @@ namespace canvas
{
_sampling_dirty = true;
}
else if( name == "anisotropy" )
{
_texture.setMaxAnisotropy( node->getFloatValue() );
}
else if( name == "additive-blend" )
{
_texture.useAdditiveBlend( node->getBoolValue() );

View File

@@ -202,6 +202,12 @@ namespace canvas
updateSampling();
}
//----------------------------------------------------------------------------
void ODGauge::setMaxAnisotropy(float anis)
{
texture->setMaxAnisotropy(anis);
}
//----------------------------------------------------------------------------
void ODGauge::setRender(bool render)
{

View File

@@ -109,6 +109,8 @@ namespace canvas
int coverage_samples = 0,
int color_samples = 0 );
void setMaxAnisotropy(float anis);
/**
* Enable/Disable updating the texture (If disabled the contents of the
* texture remains with the outcome of the last rendering pass)

View File

@@ -218,6 +218,9 @@ const float SG_RADIANS_TO_DEGREES = 180.0f / SG_PI;
#define SG_OBJECT_RANGE_ROUGH 9000.0
#define SG_OBJECT_RANGE_DETAILED 1500.0
/** Minimum expiry time of PagedLOD within the Tile. Overridden by /sim/rendering/plod-minimum-expiry-time-secs **/
#define SG_TILE_MIN_EXPIRY 180.0
/** Radius of scenery tiles in m **/
#define SG_TILE_RADIUS 14000.0

View File

@@ -3,8 +3,12 @@ include (SimGearComponent)
set(HEADERS debug_types.h
logstream.hxx BufferedLogCallback.hxx OsgIoCapture.hxx
LogCallback.hxx LogEntry.hxx)
LogCallback.hxx LogEntry.hxx
ErrorReportingCallback.hxx)
set(SOURCES logstream.cxx BufferedLogCallback.cxx
LogCallback.cxx LogEntry.cxx)
LogCallback.cxx LogEntry.cxx
ErrorReportingCallback.cxx
)
simgear_component(debug debug "${SOURCES}" "${HEADERS}")

View File

@@ -0,0 +1,47 @@
// 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.
//
#include <simgear_config.h>
#include "ErrorReportingCallback.hxx"
using std::string;
namespace simgear {
static ErrorReportCallback static_callback;
void setErrorReportCallback(ErrorReportCallback cb)
{
static_callback = cb;
}
void reportError(const std::string& msg, const std::string& more)
{
if (!static_callback)
return;
static_callback(msg, more, false);
}
void reportFatalError(const std::string& msg, const std::string& more)
{
if (!static_callback)
return;
static_callback(msg, more, true);
}
} // namespace simgear

View File

@@ -0,0 +1,31 @@
// 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.
//
#pragma once
#include <functional>
#include <string>
namespace simgear {
void reportError(const std::string& msg, const std::string& more = {});
void reportFatalError(const std::string& msg, const std::string& more = {});
using ErrorReportCallback = std::function<void(const std::string& msg, const std::string& more, bool isFatal)>;
void setErrorReportCallback(ErrorReportCallback cb);
} // namespace simgear

View File

@@ -45,14 +45,6 @@ namespace simgear
std::atomic<int> receiveDepth;
std::atomic<int> sentMessageCount;
void UnlockList()
{
_lock.unlock();
}
void LockList()
{
_lock.lock();
}
public:
Transmitter() : receiveDepth(0), sentMessageCount(0)
{
@@ -69,20 +61,17 @@ namespace simgear
// most recently registered recipients should process the messages/events first.
virtual void Register(IReceiver& r)
{
LockList();
std::lock_guard<std::mutex> scopeLock(_lock);
recipient_list.push_back(&r);
r.OnRegisteredAtTransmitter(this);
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), &r) != deleted_recipients.end())
deleted_recipients.remove(&r);
UnlockList();
}
// Removes an object from receving message from this transmitter
virtual void DeRegister(IReceiver& R)
{
LockList();
//printf("Remove %x\n", &R);
std::lock_guard<std::mutex> scopeLock(_lock);
if (recipient_list.size())
{
if (std::find(recipient_list.begin(), recipient_list.end(), &R) != recipient_list.end())
@@ -93,7 +82,6 @@ namespace simgear
deleted_recipients.push_back(&R);
}
}
UnlockList();
}
// Notify all registered recipients. Stop when receipt status of abort or finished are received.
@@ -107,69 +95,68 @@ namespace simgear
ReceiptStatus return_status = ReceiptStatusNotProcessed;
sentMessageCount++;
try
std::vector<IReceiver*> temp;
{
LockList();
std::lock_guard<std::mutex> scopeLock(_lock);
if (receiveDepth == 0)
deleted_recipients.clear();
receiveDepth++;
std::vector<IReceiver*> temp(recipient_list.size());
int idx = 0;
for (RecipientList::iterator i = recipient_list.begin(); i != recipient_list.end(); i++)
{
temp[idx++] = *i;
temp.push_back(*i);
}
UnlockList();
int tempSize = temp.size();
for (int index = 0; index < tempSize; index++)
}
int tempSize = temp.size();
for (int index = 0; index < tempSize; index++)
{
IReceiver* R = temp[index];
{
IReceiver* R = temp[index];
LockList();
std::lock_guard<std::mutex> scopeLock(_lock);
if (deleted_recipients.size())
{
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), R) != deleted_recipients.end())
{
UnlockList();
continue;
}
}
UnlockList();
if (R)
{
ReceiptStatus rstat = R->Receive(M);
switch (rstat)
{
case ReceiptStatusFail:
return_status = ReceiptStatusFail;
break;
case ReceiptStatusPending:
return_status = ReceiptStatusPending;
break;
case ReceiptStatusPendingFinished:
return rstat;
case ReceiptStatusNotProcessed:
break;
case ReceiptStatusOK:
if (return_status == ReceiptStatusNotProcessed)
return_status = rstat;
break;
case ReceiptStatusAbort:
return ReceiptStatusAbort;
case ReceiptStatusFinished:
return ReceiptStatusOK;
}
}
}
if (R)
{
ReceiptStatus rstat = R->Receive(M);
switch (rstat)
{
case ReceiptStatusFail:
return_status = ReceiptStatusFail;
break;
case ReceiptStatusPending:
return_status = ReceiptStatusPending;
break;
case ReceiptStatusPendingFinished:
return rstat;
case ReceiptStatusNotProcessed:
break;
case ReceiptStatusOK:
if (return_status == ReceiptStatusNotProcessed)
return_status = rstat;
break;
case ReceiptStatusAbort:
return ReceiptStatusAbort;
case ReceiptStatusFinished:
return ReceiptStatusOK;
}
}
}
catch (...)
{
throw;
// return_status = ReceiptStatusAbort;
}
receiveDepth--;
return return_status;
}
@@ -177,9 +164,8 @@ namespace simgear
// number of currently registered recipients
virtual int Count()
{
LockList();
std::lock_guard<std::mutex> scopeLock(_lock);
return recipient_list.size();
UnlockList();
}
// number of sent messages.

View File

@@ -46,6 +46,7 @@
#include <sstream>
#include <simgear/debug/logstream.hxx>
#include <simgear/math/sg_random.h>
#include <simgear/structure/exception.hxx>
#include "metar.hxx"
@@ -646,16 +647,21 @@ bool SGMetar::scanWind()
double gust = NaN;
if (*m == 'G') {
m++;
if (!scanNumber(&m, &i, 2, 3))
if (!strncmp(m, "//", 2)) // speed not measurable
m += 2, i = -1;
else if (!scanNumber(&m, &i, 2, 3))
return false;
gust = i;
if (i != -1)
gust = i;
}
double factor;
if (!strncmp(m, "KT", 2))
m += 2, factor = SG_KT_TO_MPS;
else if (!strncmp(m, "KMH", 3))
else if (!strncmp(m, "KMH", 3)) // invalid Km/h
m += 3, factor = SG_KMH_TO_MPS;
else if (!strncmp(m, "KPH", 3)) // ??
else if (!strncmp(m, "KPH", 3)) // invalid Km/h
m += 3, factor = SG_KMH_TO_MPS;
else if (!strncmp(m, "MPS", 3))
m += 3, factor = 1.0;
@@ -680,18 +686,28 @@ bool SGMetar::scanVariability()
{
char *m = _m;
int from, to;
if (!scanNumber(&m, &from, 3))
if (!strncmp(m, "///", 3)) // direction not measurable
m += 3, from = -1;
else if (!scanNumber(&m, &from, 3))
return false;
if (*m++ != 'V')
return false;
if (!scanNumber(&m, &to, 3))
if (!strncmp(m, "///", 3)) // direction not measurable
m += 3, to = -1;
else if (!scanNumber(&m, &to, 3))
return false;
if (!scanBoundary(&m))
return false;
_m = m;
_wind_range_from = from;
_wind_range_to = to;
_grpcount++;
return true;
}
@@ -1053,9 +1069,12 @@ bool SGMetar::scanSkyCondition()
return false;
m += i;
if (!strncmp(m, "///", 3)) // vis not measurable (e.g. because of heavy snowing)
if (!strncmp(m, "///", 3)) { // vis not measurable (e.g. because of heavy snowing)
m += 3, i = -1;
else if (scanBoundary(&m)) {
sg_srandom_time();
// randomize the base height to avoid the black sky issue
i = 50 + static_cast<int>(sg_random() * 250.0); // range [5,000, 30,000]
} else if (scanBoundary(&m)) {
_m = m;
return true; // ignore single OVC/BKN/...
} else if (!scanNumber(&m, &i, 3))

View File

@@ -81,6 +81,15 @@ void test_sensor_failure_wind()
SGMetar m1("2020/10/23 16:55 LIVD 231655Z /////KT 9999 OVC025 10/08 Q1020 RMK OVC VIS MIN 9999 BLU");
SG_CHECK_EQUAL(m1.getWindDir(), -1);
SG_CHECK_EQUAL_EP2(m1.getWindSpeed_kt(), -1, TEST_EPSILON);
SGMetar m2("2020/10/21 16:55 LIVD 211655Z /////KT CAVOK 07/03 Q1023 RMK SKC VIS MIN 9999 BLU");
SG_CHECK_EQUAL(m2.getWindDir(), -1);
SG_CHECK_EQUAL_EP2(m2.getWindSpeed_kt(), -1, TEST_EPSILON);
SGMetar m3("2020/11/17 16:00 CYAZ 171600Z 14040G//KT 10SM -RA OVC012 12/11 A2895 RMK NS8 VIA CYXY SLP806 DENSITY ALT 900FT");
SG_CHECK_EQUAL(m3.getWindDir(), 140);
SG_CHECK_EQUAL_EP2(m3.getWindSpeed_kt(), 40, TEST_EPSILON);
SG_CHECK_EQUAL_EP2(m3.getGustSpeed_kt(), SGMetarNaN, TEST_EPSILON);
}
void test_wind_unit_not_specified()

View File

@@ -61,6 +61,10 @@ public:
struct dns_ctx * ctx;
static size_t instanceCounter;
using RequestVec = std::vector<Request_ptr>;
RequestVec _activeRequests;
};
size_t Client::ClientPrivate::instanceCounter = 0;
@@ -78,6 +82,11 @@ Request::~Request()
{
}
void Request::cancel()
{
_cancelled = true;
}
bool Request::isTimeout() const
{
return (time(NULL) - _start) > _timeout_secs;
@@ -114,18 +123,20 @@ static void dnscbSRV(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data)
{
SRVRequest * r = static_cast<SRVRequest*>(data);
if (result) {
r->cname = result->dnssrv_cname;
r->qname = result->dnssrv_qname;
r->ttl = result->dnssrv_ttl;
for (int i = 0; i < result->dnssrv_nrr; i++) {
SRVRequest::SRV_ptr srv(new SRVRequest::SRV);
r->entries.push_back(srv);
srv->priority = result->dnssrv_srv[i].priority;
srv->weight = result->dnssrv_srv[i].weight;
srv->port = result->dnssrv_srv[i].port;
srv->target = result->dnssrv_srv[i].name;
if (!r->isCancelled()) {
r->cname = result->dnssrv_cname;
r->qname = result->dnssrv_qname;
r->ttl = result->dnssrv_ttl;
for (int i = 0; i < result->dnssrv_nrr; i++) {
SRVRequest::SRV_ptr srv(new SRVRequest::SRV);
r->entries.push_back(srv);
srv->priority = result->dnssrv_srv[i].priority;
srv->weight = result->dnssrv_srv[i].weight;
srv->port = result->dnssrv_srv[i].port;
srv->target = result->dnssrv_srv[i].name;
}
std::sort(r->entries.begin(), r->entries.end(), sortSRV);
}
std::sort( r->entries.begin(), r->entries.end(), sortSRV );
free(result);
}
r->setComplete();
@@ -134,11 +145,16 @@ static void dnscbSRV(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data)
void SRVRequest::submit( Client * client )
{
// if service is defined, pass service and protocol
if (!dns_submit_srv(client->d->ctx, getDn().c_str(), _service.empty() ? NULL : _service.c_str(), _service.empty() ? NULL : _protocol.c_str(), 0, dnscbSRV, this )) {
auto q = dns_submit_srv(client->d->ctx, getDn().c_str(), _service.empty() ? NULL : _service.c_str(),
_service.empty() ? NULL : _protocol.c_str(),
0, dnscbSRV, this);
if (!q) {
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
return;
}
_start = time(NULL);
_query = q;
}
TXTRequest::TXTRequest( const std::string & dn ) :
@@ -151,22 +167,24 @@ static void dnscbTXT(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data)
{
TXTRequest * r = static_cast<TXTRequest*>(data);
if (result) {
r->cname = result->dnstxt_cname;
r->qname = result->dnstxt_qname;
r->ttl = result->dnstxt_ttl;
for (int i = 0; i < result->dnstxt_nrr; i++) {
//TODO: interprete the .len field of dnstxt_txt?
auto rawTxt = reinterpret_cast<char*>(result->dnstxt_txt[i].txt);
if (!rawTxt) {
continue;
}
if (!r->isCancelled()) {
r->cname = result->dnstxt_cname;
r->qname = result->dnstxt_qname;
r->ttl = result->dnstxt_ttl;
for (int i = 0; i < result->dnstxt_nrr; i++) {
//TODO: interprete the .len field of dnstxt_txt?
auto rawTxt = reinterpret_cast<char*>(result->dnstxt_txt[i].txt);
if (!rawTxt) {
continue;
}
const string txt{rawTxt};
r->entries.push_back(txt);
string_list tokens = simgear::strutils::split( txt, "=", 1 );
if( tokens.size() == 2 ) {
r->attributes[tokens[0]] = tokens[1];
}
const string txt{rawTxt};
r->entries.push_back(txt);
string_list tokens = simgear::strutils::split(txt, "=", 1);
if (tokens.size() == 2) {
r->attributes[tokens[0]] = tokens[1];
}
}
}
free(result);
}
@@ -176,11 +194,13 @@ static void dnscbTXT(struct dns_ctx *ctx, struct dns_rr_txt *result, void *data)
void TXTRequest::submit( Client * client )
{
// protocol and service an already encoded in DN so pass in NULL for both
if (!dns_submit_txt(client->d->ctx, getDn().c_str(), DNS_C_IN, 0, dnscbTXT, this )) {
auto q = dns_submit_txt(client->d->ctx, getDn().c_str(), DNS_C_IN, 0, dnscbTXT, this);
if (!q) {
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
return;
}
_start = time(NULL);
_query = q;
}
@@ -195,27 +215,29 @@ static void dnscbNAPTR(struct dns_ctx *ctx, struct dns_rr_naptr *result, void *d
{
NAPTRRequest * r = static_cast<NAPTRRequest*>(data);
if (result) {
r->cname = result->dnsnaptr_cname;
r->qname = result->dnsnaptr_qname;
r->ttl = result->dnsnaptr_ttl;
for (int i = 0; i < result->dnsnaptr_nrr; i++) {
if( !r->qservice.empty() && r->qservice != result->dnsnaptr_naptr[i].service )
continue;
if (!r->isCancelled()) {
r->cname = result->dnsnaptr_cname;
r->qname = result->dnsnaptr_qname;
r->ttl = result->dnsnaptr_ttl;
for (int i = 0; i < result->dnsnaptr_nrr; i++) {
if (!r->qservice.empty() && r->qservice != result->dnsnaptr_naptr[i].service)
continue;
//TODO: case ignore and result flags may have more than one flag
if( !r->qflags.empty() && r->qflags != result->dnsnaptr_naptr[i].flags )
continue;
//TODO: case ignore and result flags may have more than one flag
if (!r->qflags.empty() && r->qflags != result->dnsnaptr_naptr[i].flags)
continue;
NAPTRRequest::NAPTR_ptr naptr(new NAPTRRequest::NAPTR);
r->entries.push_back(naptr);
naptr->order = result->dnsnaptr_naptr[i].order;
naptr->preference = result->dnsnaptr_naptr[i].preference;
naptr->flags = result->dnsnaptr_naptr[i].flags;
naptr->service = result->dnsnaptr_naptr[i].service;
naptr->regexp = result->dnsnaptr_naptr[i].regexp;
naptr->replacement = result->dnsnaptr_naptr[i].replacement;
NAPTRRequest::NAPTR_ptr naptr(new NAPTRRequest::NAPTR);
r->entries.push_back(naptr);
naptr->order = result->dnsnaptr_naptr[i].order;
naptr->preference = result->dnsnaptr_naptr[i].preference;
naptr->flags = result->dnsnaptr_naptr[i].flags;
naptr->service = result->dnsnaptr_naptr[i].service;
naptr->regexp = result->dnsnaptr_naptr[i].regexp;
naptr->replacement = result->dnsnaptr_naptr[i].replacement;
}
std::sort(r->entries.begin(), r->entries.end(), sortNAPTR);
}
std::sort( r->entries.begin(), r->entries.end(), sortNAPTR );
free(result);
}
r->setComplete();
@@ -223,11 +245,13 @@ static void dnscbNAPTR(struct dns_ctx *ctx, struct dns_rr_naptr *result, void *d
void NAPTRRequest::submit( Client * client )
{
if (!dns_submit_naptr(client->d->ctx, getDn().c_str(), 0, dnscbNAPTR, this )) {
auto q = dns_submit_naptr(client->d->ctx, getDn().c_str(), 0, dnscbNAPTR, this);
if (!q) {
SG_LOG(SG_IO, SG_ALERT, "Can't submit dns request for " << getDn());
return;
}
_start = time(NULL);
_query = q;
}
@@ -242,6 +266,7 @@ Client::Client() :
void Client::makeRequest(const Request_ptr& r)
{
d->_activeRequests.push_back(r);
r->submit(this);
}
@@ -252,6 +277,19 @@ void Client::update(int waitTimeout)
return;
dns_ioevent(d->ctx, now);
// drop our owning ref to completed requests,
// and cancel any which timed out
auto it = std::remove_if(d->_activeRequests.begin(), d->_activeRequests.end(),
[this](const Request_ptr& r) {
if (r->isTimeout()) {
dns_cancel(d->ctx, reinterpret_cast<struct dns_query*>(r->_query));
return true;
}
return r->isComplete();
});
d->_activeRequests.erase(it, d->_activeRequests.end());
}
} // of namespace DNS

View File

@@ -40,28 +40,38 @@ namespace DNS
{
class Client;
using UDNSQueryPtr = void*;
class Request : public SGReferenced
{
public:
Request( const std::string & dn );
virtual ~Request();
std::string getDn() const { return _dn; }
const std::string& getDn() const { return _dn; }
int getType() const { return _type; }
bool isComplete() const { return _complete; }
bool isTimeout() const;
void setComplete( bool b = true ) { _complete = b; }
bool isCancelled() const { return _cancelled; }
virtual void submit( Client * client) = 0;
void cancel();
std::string cname;
std::string qname;
unsigned ttl;
protected:
friend class Client;
UDNSQueryPtr _query = nullptr;
std::string _dn;
int _type;
bool _complete;
time_t _timeout_secs;
time_t _start;
bool _cancelled = false;
};
typedef SGSharedPtr<Request> Request_ptr;
@@ -69,7 +79,7 @@ class NAPTRRequest : public Request
{
public:
NAPTRRequest( const std::string & dn );
virtual void submit( Client * client );
void submit(Client* client) override;
struct NAPTR : SGReferenced {
int order;
@@ -92,7 +102,7 @@ class SRVRequest : public Request
public:
SRVRequest( const std::string & dn );
SRVRequest( const std::string & dn, const string & service, const string & protocol );
virtual void submit( Client * client );
void submit(Client* client) override;
struct SRV : SGReferenced {
int priority;
@@ -112,7 +122,7 @@ class TXTRequest : public Request
{
public:
TXTRequest( const std::string & dn );
virtual void submit( Client * client );
void submit(Client* client) override;
typedef std::vector<string> TXT_list;
typedef std::map<std::string,std::string> TXT_Attribute_map;

View File

@@ -437,32 +437,37 @@ public:
ArchiveExtractTask(const ArchiveExtractTask &) = delete;
HTTPRepoPrivate::ProcessResult run(HTTPRepoPrivate *repo) {
size_t rd = file.read((char *)buffer, bufferSize);
extractor.extractBytes(buffer, rd);
if (file.eof()) {
extractor.flush();
file.close();
if (!extractor.isAtEndOfArchive()) {
SG_LOG(SG_TERRASYNC, SG_ALERT, "Corrupt tarball " << relativePath);
repo->failedToUpdateChild(relativePath,
HTTPRepository::REPO_ERROR_IO);
return HTTPRepoPrivate::ProcessFailed;
HTTPRepoPrivate::ProcessResult run(HTTPRepoPrivate* repo)
{
if (!buffer) {
return HTTPRepoPrivate::ProcessFailed;
}
if (extractor.hasError()) {
SG_LOG(SG_TERRASYNC, SG_ALERT, "Error extracting " << relativePath);
repo->failedToUpdateChild(relativePath,
HTTPRepository::REPO_ERROR_IO);
return HTTPRepoPrivate::ProcessFailed;
size_t rd = file.read((char*)buffer, bufferSize);
extractor.extractBytes(buffer, rd);
if (file.eof()) {
extractor.flush();
file.close();
if (!extractor.isAtEndOfArchive()) {
SG_LOG(SG_TERRASYNC, SG_ALERT, "Corrupt tarball " << relativePath);
repo->failedToUpdateChild(relativePath,
HTTPRepository::REPO_ERROR_IO);
return HTTPRepoPrivate::ProcessFailed;
}
if (extractor.hasError()) {
SG_LOG(SG_TERRASYNC, SG_ALERT, "Error extracting " << relativePath);
repo->failedToUpdateChild(relativePath,
HTTPRepository::REPO_ERROR_IO);
return HTTPRepoPrivate::ProcessFailed;
}
return HTTPRepoPrivate::ProcessDone;
}
return HTTPRepoPrivate::ProcessDone;
}
return HTTPRepoPrivate::ProcessContinue;
return HTTPRepoPrivate::ProcessContinue;
}
~ArchiveExtractTask() { free(buffer); }
@@ -976,49 +981,71 @@ HTTPRepository::failure() const
}
protected:
void gotBodyData(const char *s, int n) override {
if (!file.get()) {
file.reset(new SGBinaryFile(pathInRepo));
if (!file->open(SG_IO_OUT)) {
SG_LOG(SG_TERRASYNC, SG_WARN,
"unable to create file " << pathInRepo);
_directory->repository()->http->cancelRequest(
this, "Unable to create output file:" + pathInRepo.utf8Str());
}
void gotBodyData(const char* s, int n) override
{
if (!file.get()) {
const bool ok = createOutputFile();
if (!ok) {
_directory->repository()->http->cancelRequest(
this, "Unable to create output file:" + pathInRepo.utf8Str());
}
}
sha1_init(&hashContext);
sha1_write(&hashContext, s, n);
file->write(s, n);
}
sha1_write(&hashContext, s, n);
file->write(s, n);
}
bool createOutputFile()
{
file.reset(new SGBinaryFile(pathInRepo));
if (!file->open(SG_IO_OUT)) {
SG_LOG(SG_TERRASYNC, SG_WARN,
"unable to create file " << pathInRepo);
return false;
}
void onDone() override {
file->close();
if (responseCode() == 200) {
std::string hash =
strutils::encodeHex(sha1_result(&hashContext), HASH_LENGTH);
_directory->didUpdateFile(fileName, hash, contentSize());
} else if (responseCode() == 404) {
SG_LOG(SG_TERRASYNC, SG_WARN,
"terrasync file not found on server: "
<< fileName << " for " << _directory->absolutePath());
_directory->didFailToUpdateFile(
fileName, HTTPRepository::REPO_ERROR_FILE_NOT_FOUND);
} else {
SG_LOG(SG_TERRASYNC, SG_WARN,
"terrasync file download error on server: "
<< fileName << " for " << _directory->absolutePath()
<< "\n\tserver responded: " << responseCode() << "/"
<< responseReason());
_directory->didFailToUpdateFile(fileName,
HTTPRepository::REPO_ERROR_HTTP);
// should we every retry here?
sha1_init(&hashContext);
return true;
}
_directory->repository()->finishedRequest(
this, HTTPRepoPrivate::RequestFinish::Done);
}
void onDone() override
{
const bool is200Response = (responseCode() == 200);
if (!file && is200Response) {
// if the server defines a zero-byte file, we will never call
// gotBodyData, so create the file here
// this ensures all the logic below works as expected
createOutputFile();
}
if (file) {
file->close();
}
if (is200Response) {
std::string hash =
strutils::encodeHex(sha1_result(&hashContext), HASH_LENGTH);
_directory->didUpdateFile(fileName, hash, contentSize());
} else if (responseCode() == 404) {
SG_LOG(SG_TERRASYNC, SG_WARN,
"terrasync file not found on server: "
<< fileName << " for " << _directory->absolutePath());
_directory->didFailToUpdateFile(
fileName, HTTPRepository::REPO_ERROR_FILE_NOT_FOUND);
} else {
SG_LOG(SG_TERRASYNC, SG_WARN,
"terrasync file download error on server: "
<< fileName << " for " << _directory->absolutePath()
<< "\n\tserver responded: " << responseCode() << "/"
<< responseReason());
_directory->didFailToUpdateFile(fileName,
HTTPRepository::REPO_ERROR_HTTP);
// should we every retry here?
}
_directory->repository()->finishedRequest(
this, HTTPRepoPrivate::RequestFinish::Done);
}
void onFail() override {
HTTPRepository::ResultCode code = HTTPRepository::REPO_ERROR_SOCKET;

View File

@@ -566,8 +566,10 @@ bool SGBinObject::read_bin( const SGPath& file ) {
sgReadUInt( fp, &header );
if (sgReadError()) {
int code = 0;
const char* gzErrorString = gzerror(fp, &code);
gzclose(fp);
throw sg_io_exception("Unable to read BTG header: " + simgear::strutils::error_string(errno), sg_location(file));
throw sg_io_exception("Unable to read BTG header: " + string{gzErrorString} + ", code =" + std::to_string(code), sg_location(file));
}
if ( ((header & 0xFF000000) >> 24) == 'S' &&

View File

@@ -31,6 +31,10 @@ using TestApi = simgear::HTTP::TestApi;
std::string dataForFile(const std::string& parentName, const std::string& name, int revision)
{
if (name == "zeroByteFile") {
return {};
}
std::ostringstream os;
// random content but which definitely depends on our tree location
// and revision.
@@ -446,6 +450,7 @@ void testBasicClone(HTTP::Client* cl)
verifyFileState(p, "fileA");
verifyFileState(p, "dirA/subdirA/fileAAA");
verifyFileState(p, "dirC/subdirA/subsubA/fileCAAA");
verifyFileState(p, "dirA/subdirA/zeroByteFile");
global_repo->findEntry("fileA")->revision++;
global_repo->findEntry("dirB/subdirA/fileBAA")->revision++;
@@ -911,6 +916,8 @@ int main(int argc, char* argv[])
global_repo->defineFile("dirA/fileAC");
global_repo->defineFile("dirA/subdirA/fileAAA");
global_repo->defineFile("dirA/subdirA/fileAAB");
global_repo->defineFile("dirA/subdirA/zeroByteFile");
global_repo->defineFile("dirB/subdirA/fileBAA");
global_repo->defineFile("dirB/subdirA/fileBAB");
global_repo->defineFile("dirB/subdirA/fileBAC");

View File

@@ -511,32 +511,34 @@ public:
const size_t BUFFER_SIZE = 1024 * 1024;
void* buf = malloc(BUFFER_SIZE);
try {
int result = unzGoToFirstFile(zip);
if (result != UNZ_OK) {
throw sg_exception("failed to go to first file in archive");
}
while (true) {
extractCurrentFile(zip, (char*)buf, BUFFER_SIZE);
if (state == FILTER_STOPPED) {
break;
}
result = unzGoToNextFile(zip);
if (result == UNZ_END_OF_LIST_OF_FILE) {
break;
}
else if (result != UNZ_OK) {
throw sg_io_exception("failed to go to next file in the archive");
}
}
state = END_OF_ARCHIVE;
}
catch (sg_exception&) {
int result = unzGoToFirstFile(zip);
if (result != UNZ_OK) {
SG_LOG(SG_IO, SG_ALERT, outer->rootPath() << "failed to go to first file in archive:" << result);
state = BAD_ARCHIVE;
free(buf);
unzClose(zip);
return;
}
while (true) {
extractCurrentFile(zip, (char*)buf, BUFFER_SIZE);
if (state == FILTER_STOPPED) {
state = END_OF_ARCHIVE;
break;
}
result = unzGoToNextFile(zip);
if (result == UNZ_END_OF_LIST_OF_FILE) {
state = END_OF_ARCHIVE;
break;
} else if (result != UNZ_OK) {
SG_LOG(SG_IO, SG_ALERT, outer->rootPath() << "failed to go to next file in archive:" << result);
state = BAD_ARCHIVE;
break;
}
}
free(buf);
unzClose(zip);
}

View File

@@ -70,6 +70,11 @@ public:
Stop
};
SGPath rootPath() const
{
return _rootPath;
}
protected:

View File

@@ -29,6 +29,13 @@ public:
/// Default constructor, initializes the instance to lat = lon = elev = 0
SGGeod(void);
/**
return an SGGeod for which isValid() returns false.
This is necessaerby becuase for historical reasons, ther defaulrt constructor above initialsies to zero,zero,zero
which *is*
*/
static SGGeod invalid();
/// Factory from angular values in radians and elevation is 0
static SGGeod fromRad(double lon, double lat);
/// Factory from angular values in degrees and elevation is 0

View File

@@ -663,3 +663,8 @@ SGGeodesy::radialIntersection(const SGGeod& a, double aRadial,
result = SGGeod::fromGeoc(r);
return true;
}
SGGeod SGGeod::invalid()
{
return SGGeod::fromDeg(-999.9, -999.0);
}

View File

@@ -248,7 +248,7 @@ void naFreeContext(naContext c)
// than I have right now. So instead I'm clearing the stack tops here, so
// a freed context looks the same as a new one returned by initContext.
c->fTop = c->opTop = c->markTop = 0;
c->fTop = c->opTop = c->markTop = c->ntemps = 0;
c->nextFree = globals->freeContexts;
globals->freeContexts = c;

View File

@@ -63,7 +63,7 @@ namespace nasal
class NasalMainLoopRecipient : public simgear::Emesary::IReceiver {
public:
NasalMainLoopRecipient() : receiveCount(0) {
NasalMainLoopRecipient() : receiveCount(0), Active(false), CanWait(false) {
simgear::Emesary::GlobalTransmitter::instance()->Register(*this);
}
virtual ~NasalMainLoopRecipient() {

View File

@@ -100,7 +100,14 @@ naRef naNewHash(struct Context* c)
naRef naNewCode(struct Context* c)
{
return naNew(c, T_CODE);
naRef r = naNew(c, T_CODE);
// naNew can return a previously used naCode. naCodeGen will init
// all these members but a GC can occur inside naCodeGen, so we see
// partially initalized state here. To avoid this, clear out the values
// which mark() cares about.
PTR(r).code->srcFile = naNil();
PTR(r).code->nConstants = 0;
return r;
}
naRef naNewCCode(struct Context* c, naCFunction fptr)

View File

@@ -133,7 +133,9 @@ public:
void fireRefreshStatus(CatalogRef catalog, Delegate::StatusCode status)
{
for (auto d : delegates) {
// take a copy of delegates since firing this can modify the data
const auto currentDelegates = delegates;
for (auto d : currentDelegates) {
d->catalogRefreshed(catalog, status);
}
}
@@ -722,12 +724,6 @@ void Root::catalogRefreshStatus(CatalogRef aCat, Delegate::StatusCode aReason)
auto catIt = d->catalogs.find(aCat->id());
d->fireRefreshStatus(aCat, aReason);
if (aReason == Delegate::STATUS_IN_PROGRESS) {
d->refreshing.insert(aCat);
} else {
d->refreshing.erase(aCat);
}
if (aCat->isUserEnabled() &&
(aReason == Delegate::STATUS_REFRESHED) &&
(catIt == d->catalogs.end()))
@@ -761,6 +757,17 @@ void Root::catalogRefreshStatus(CatalogRef aCat, Delegate::StatusCode aReason)
}
} // of catalog is disabled
// remove from refreshing /after/ checking for enable / disabled, since for
// new catalogs, the reference in d->refreshing might be our /only/
// reference to the catalog. Once the refresh is done (either failed or
// succeeded) the Catalog will be in either d->catalogs or
// d->disabledCatalogs
if (aReason == Delegate::STATUS_IN_PROGRESS) {
d->refreshing.insert(aCat);
} else {
d->refreshing.erase(aCat);
}
if (d->refreshing.empty()) {
d->fireRefreshStatus(CatalogRef(), Delegate::STATUS_REFRESHED);
d->firePackagesChanged();

View File

@@ -19,6 +19,10 @@
#include <sstream>
#include <iomanip>
#include <iterator>
#include <exception> // can't use sg_exception becuase of PROPS_STANDALONE
#include <mutex>
#include <thread>
#include <stdio.h>
#include <string.h>
@@ -51,11 +55,15 @@ using namespace simgear;
struct SGPropertyNodeListeners
{
/* Protect _num_iterators and _items. We use a recursive mutex to allow
nested access to work as normal. */
std::recursive_mutex _rmutex;
/* This keeps a count of the current number of nested invocations of
forEachListener(). If non-zero, other code higher up the stack is iterating
_items[] so for example code must not erase items in the vector. */
int _num_iterators = 0;
std::vector<SGPropertyChangeListener *> _items;
};
@@ -558,23 +566,15 @@ find_node (SGPropertyNode * current,
}
}
#else
template<typename Range>
SGPropertyNode*
find_node (SGPropertyNode * current,
const Range& path,
bool create,
int last_index = -1)
{
template <typename Range>
SGPropertyNode *find_node(SGPropertyNode *current, const Range &path,
bool create, int last_index = -1) {
using namespace boost;
typedef split_iterator<typename range_result_iterator<Range>::type>
PathSplitIterator;
PathSplitIterator itr
= make_split_iterator(path, first_finder("/", is_equal()));
auto itr = make_split_iterator(path, first_finder("/", is_equal()));
if (*path.begin() == '/')
return find_node_aux(current->getRootNode(), itr, create, last_index);
else
return find_node_aux(current, itr, create, last_index);
else
return find_node_aux(current, itr, create, last_index);
}
#endif
@@ -2406,6 +2406,7 @@ SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
if (_listeners == 0)
_listeners = new SGPropertyNodeListeners;
std::lock_guard<std::recursive_mutex> lock(_listeners->_rmutex);
/* If there's a nullptr entry (a listener that was unregistered), we
overwrite it. This ensures that listeners that routinely unregister+register
themselves don't make _listeners->_items grow unnecessarily. Otherwise simply
@@ -2429,9 +2430,13 @@ SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
{
if (_listeners == 0)
return;
/* We use a std::unique_lock rather than a std::lock_guard because we may
need to unlock early. */
std::unique_lock<std::recursive_mutex> lock(_listeners->_rmutex);
vector<SGPropertyChangeListener*>::iterator it =
find(_listeners->_items.begin(), _listeners->_items.end(), listener);
if (it != _listeners->_items.end()) {
assert(_listeners->_num_iterators >= 0);
if (_listeners->_num_iterators) {
/* _listeners._items is currently being iterated further up the stack in
this thread by one or more nested invocations of forEachListener(), so
@@ -2450,6 +2455,7 @@ SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
_listeners->_items.erase(it);
listener->unregister_property(this);
if (_listeners->_items.empty()) {
lock.unlock();
delete _listeners;
_listeners = 0;
}
@@ -2511,9 +2517,11 @@ static void forEachListener(
)
{
if (!_listeners) return;
std::lock_guard<std::recursive_mutex> lock(_listeners->_rmutex);
assert(_listeners->_num_iterators >= 0);
_listeners->_num_iterators += 1;
/* We need to use an index here when iterating _listeners->_items, not an
iterator. This is because a listener may add new listeners, causing the
vector to be reallocated, which would invalidate any iterator. */
@@ -2528,10 +2536,12 @@ static void forEachListener(
}
}
}
_listeners->_num_iterators -= 1;
assert(_listeners->_num_iterators >= 0);
if (_listeners->_num_iterators == 0) {
/* Remove any items that have been set to nullptr. */
_listeners->_items.erase(
std::remove(_listeners->_items.begin(), _listeners->_items.end(), (SGPropertyChangeListener*) nullptr),
@@ -2547,6 +2557,7 @@ static void forEachListener(
int SGPropertyNode::nListeners() const
{
if (!_listeners) return 0;
std::lock_guard<std::recursive_mutex> lock(_listeners->_rmutex);
int n = 0;
for (auto listener: _listeners->_items) {
if (listener) n += 1;

View File

@@ -76,7 +76,7 @@
#include <simgear/structure/SGExpression.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/props/vectorPropTemplates.hxx>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/io/iostreams/sgstream.hxx>
namespace simgear
@@ -928,7 +928,8 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
// FIXME orig: const string& shaderName = shaderKey.first;
string shaderName = shaderKey.first;
Shader::Type stype = (Shader::Type)shaderKey.second;
if (getPropertyRoot()->getBoolValue("/sim/version/compositor-support", false) &&
const bool compositorEnabled = getPropertyRoot()->getBoolValue("/sim/version/compositor-support", false);
if (compositorEnabled &&
shaderName.substr(0, shaderName.find("/")) == "Shaders") {
shaderName = "Compositor/" + shaderName;
}
@@ -936,7 +937,9 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
if (fileName.empty())
{
SG_LOG(SG_INPUT, SG_ALERT, "Could not locate shader" << shaderName);
if (!compositorEnabled) {
reportError("Missing shader", shaderName);
}
throw BuilderException(string("couldn't find shader ") +
shaderName);
@@ -1481,10 +1484,8 @@ void mergeSchemesFallbacks(Effect *effect, const SGReaderWriterOptions *options)
// Walk the techniques property tree, building techniques and
// passes.
static std::mutex realizeTechniques_lock;
bool Effect::realizeTechniques(const SGReaderWriterOptions* options)
{
std::lock_guard<std::mutex> g(realizeTechniques_lock);
if (getPropertyRoot()->getBoolValue("/sim/version/compositor-support", false))
mergeSchemesFallbacks(this, options);

View File

@@ -273,11 +273,19 @@ bool setAttrs(const TexTuple& attrs, Texture* tex,
options->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS_NORMALIZED);
else
options->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS);
#if OSG_VERSION_LESS_THAN(3,4,2)
result = osgDB::readImageFile(imageName, options);
#else
result = osgDB::readRefImageFile(imageName, options);
#endif
try {
#if OSG_VERSION_LESS_THAN(3,4,2)
result = osgDB::readImageFile(imageName, options);
#else
result = osgDB::readRefImageFile(imageName, options);
#endif
} catch (std::bad_alloc& ba) {
SG_LOG(SG_GL, SG_ALERT, "Bad allocation loading:" << imageName);
// todo: report low memory warning
return false;
}
options->setLoadOriginHint(origLOH);
osg::ref_ptr<osg::Image> image;
if (result.success())

View File

@@ -393,6 +393,10 @@ ModelRegistry::readImage(const string& fileName,
isEffect = true;
// can_compress = false;
}
else if (sgoptC && !transparent && sgoptC->getLoadOriginHint() == SGReaderWriterOptions::LoadOriginHint::ORIGIN_CANVAS) {
SG_LOG(SG_IO, SG_INFO, "From Canvas " + absFileName + " will generate mipmap only");
can_compress = false;
}
if (can_compress)
{
std::string pot_message;

View File

@@ -1135,16 +1135,8 @@ void SpinAnimCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
double intPart;
double rot = modf(rotation, &intPart);
double angle = rot * 2.0 * osg::PI;
const SGVec3d& sgcenter = transform->getCenter();
const SGVec3d& sgaxis = transform->getAxis();
Matrixd mat = Matrixd::translate(-sgcenter[0], -sgcenter[1], -sgcenter[2])
* Matrixd::rotate(angle, sgaxis[0], sgaxis[1], sgaxis[2])
* Matrixd::translate(sgcenter[0], sgcenter[1], sgcenter[2])
* *cv->getModelViewMatrix();
ref_ptr<RefMatrix> refmat = new RefMatrix(mat);
cv->pushModelViewMatrix(refmat.get(), transform->getReferenceFrame());
transform->setAngleRad(angle);
traverse(transform, nv);
cv->popModelViewMatrix();
} else {
traverse(transform, nv);
}

View File

@@ -294,7 +294,7 @@ ReaderWriterSPT::createTree(const BucketBox& bucketBox, const LocalOptions& opti
osg::ref_ptr<osg::Node>
ReaderWriterSPT::createPagedLOD(const BucketBox& bucketBox, const LocalOptions& options) const
{
osg::PagedLOD* pagedLOD = new osg::PagedLOD;
osg::ref_ptr<osg::PagedLOD> pagedLOD = new osg::PagedLOD;
pagedLOD->setCenterMode(osg::PagedLOD::USER_DEFINED_CENTER);
SGSpheref sphere = bucketBox.getBoundingSphere();

View File

@@ -212,7 +212,8 @@ struct ReaderWriterSTG::_ModelBin {
STGObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD()));
quadtree.buildQuadTree(_objectStaticList.begin(), _objectStaticList.end());
osg::ref_ptr<osg::Group> group = quadtree.getRoot();
group->setName("STG-group-A");
string group_name = string("STG-group-A ").append(_bucket.gen_index_str());
group->setName(group_name);
group->setDataVariance(osg::Object::STATIC);
simgear::AirportSignBuilder signBuilder(_options->getMaterialLib(), _bucket.get_center());
@@ -586,10 +587,12 @@ struct ReaderWriterSTG::_ModelBin {
{
osg::ref_ptr<SGReaderWriterOptions> options;
options = SGReaderWriterOptions::copyOrCreate(opt);
float pagedLODExpiry = atoi(options->getPluginStringData("SimGear::PAGED_LOD_EXPIRY").c_str());
osg::ref_ptr<osg::Group> terrainGroup = new osg::Group;
terrainGroup->setDataVariance(osg::Object::STATIC);
terrainGroup->setName("terrain");
std::string terrain_name = string("terrain ").append(bucket.gen_index_str());
terrainGroup->setName(terrain_name);
if (_foundBase) {
for (auto stgObject : _objectList) {
@@ -637,11 +640,13 @@ struct ReaderWriterSTG::_ModelBin {
} else {
osg::PagedLOD* pagedLOD = new osg::PagedLOD;
pagedLOD->setCenterMode(osg::PagedLOD::USE_BOUNDING_SPHERE_CENTER);
pagedLOD->setName("pagedObjectLOD");
std::string name = string("pagedObjectLOD ").append(bucket.gen_index_str());
pagedLOD->setName(name);
// This should be visible in any case.
// If this is replaced by some lower level of detail, the parent LOD node handles this.
pagedLOD->addChild(terrainGroup, 0, std::numeric_limits<float>::max());
pagedLOD->setMinimumExpiryTime(0, pagedLODExpiry);
// we just need to know about the read file callback that itself holds the data
osg::ref_ptr<DelayLoadReadFileCallback> readFileCallback = new DelayLoadReadFileCallback;
@@ -658,10 +663,11 @@ struct ReaderWriterSTG::_ModelBin {
// Objects may end up displayed up to 2x the object range.
pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 2.0 * _object_range_rough);
pagedLOD->setMinimumExpiryTime(pagedLOD->getNumChildren(), pagedLODExpiry);
pagedLOD->setRadius(SG_TILE_RADIUS);
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile PagedLOD Center: " << pagedLOD->getCenter().x() << "," << pagedLOD->getCenter().y() << "," << pagedLOD->getCenter().z() );
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile PagedLOD Range: " << (2.0 * _object_range_rough));
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile PagedLOD Radius: " << SG_TILE_RADIUS);
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Center: " << pagedLOD->getCenter().x() << "," << pagedLOD->getCenter().y() << "," << pagedLOD->getCenter().z() );
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Range: " << (2.0 * _object_range_rough));
SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile " << bucket.gen_index_str() << " PagedLOD Radius: " << SG_TILE_RADIUS);
return pagedLOD;
}
}

View File

@@ -441,6 +441,10 @@ typedef QuadTreeBuilder<LOD*, SGBuildingBin::BuildingInstance, MakeBuildingLeaf,
if (hash_pos != std::string::npos)
line.resize(hash_pos);
if (line.empty()) {
continue; // skip blank lines
}
// and process further
std::stringstream in(line);

View File

@@ -41,6 +41,7 @@
#include <simgear/scene/material/EffectGeode.hxx>
#include <simgear/scene/material/mat.hxx>
#include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/model/BoundingVolumeBuildVisitor.hxx>
#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/util/VectorArrayAdapter.hxx>
#include <simgear/scene/util/SGNodeMasks.hxx>
@@ -340,5 +341,10 @@ osg::Node* SGOceanTile(const SGBucket& b, SGMaterialLib *matlib, int latPoints,
transform->addChild(geode);
transform->setNodeMask( ~(simgear::CASTSHADOW_BIT | simgear::MODELLIGHT_BIT) );
// Create a BVH at this point. This is normally provided by the file loader, but as we create the
// geometry programmatically, no file loader is involved.
BoundingVolumeBuildVisitor bvhBuilder(false);
transform->accept(bvhBuilder);
return transform;
}

View File

@@ -572,6 +572,15 @@ void SGTerraSync::WorkerThread::updateSyncSlot(SyncSlot &slot)
notFound(slot.currentItem);
} else if (res != HTTPRepository::REPO_NO_ERROR) {
fail(slot.currentItem);
// in case the Airports_archive download fails, create the
// directory, so that next sync, we do a manual sync
if ((slot.currentItem._type == SyncItem::AirportData) && slot.isNewDirectory) {
SG_LOG(SG_TERRASYNC, SG_ALERT, "Failed to download Airports_archive, will download discrete files next time");
simgear::Dir d(_local_dir + "/Airports");
d.create(0755);
_completedTiles.erase(slot.currentItem._dir);
}
} else {
updated(slot.currentItem, slot.isNewDirectory);
SG_LOG(SG_TERRASYNC, SG_DEBUG, "sync of " << slot.repository->baseUrl() << " finished ("

View File

@@ -46,6 +46,7 @@ public:
ORIGIN_EFFECTS,
ORIGIN_EFFECTS_NORMALIZED,
ORIGIN_SPLASH_SCREEN,
ORIGIN_CANVAS,
};
//SGReaderWriterOptions* cloneOptions(const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) const { return static_cast<SGReaderWriterOptions*>(clone(copyop)); }

View File

@@ -441,7 +441,7 @@ void StateMachine::initFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
std::string nm = stateDesc->getStringValue("name");
if (nm.empty()) {
SG_LOG(SG_GENERAL, SG_ALERT, "No name found for state in branch " << path);
SG_LOG(SG_GENERAL, SG_DEV_ALERT, "No name found for state in branch " << path);
throw sg_exception("No name element in state");
}
@@ -464,8 +464,8 @@ void StateMachine::initFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
std::string target_id = tDesc->getStringValue("target");
if (nm.empty()) {
SG_LOG(SG_GENERAL, SG_ALERT, "No name found for transition in branch " << path);
throw sg_exception("No name element in transition");
SG_LOG(SG_GENERAL, SG_DEV_WARN, "No name found for transition in branch " << path);
nm = "transition-to-" + target_id;
}
if (target_id.empty()) {

View File

@@ -30,9 +30,10 @@
#include "subsystem_mgr.hxx"
#include "commands.hxx"
#include <simgear/props/props.hxx>
#include <simgear/math/SGMath.hxx>
#include "SGSmplstat.hxx"
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/math/SGMath.hxx>
#include <simgear/props/props.hxx>
const int SG_MAX_SUBSYSTEM_EXCEPTIONS = 4;
const char SUBSYSTEM_NAME_SEPARATOR = '.';
@@ -828,8 +829,18 @@ SGSubsystemGroup::Member::update (double delta_time_sec)
if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) {
SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount <<
", suspending)");
simgear::reportError("suspending subsystem after too many errors:" + name);
subsystem->suspend();
}
} catch (std::bad_alloc& ba) {
// attempting to track down source of these on Sentry.io
SG_LOG(SG_GENERAL, SG_ALERT, "caught bad_alloc processing subsystem:" << name);
simgear::reportError("caught bad_alloc processing subsystem:" + name);
if (++exceptionCount > SG_MAX_SUBSYSTEM_EXCEPTIONS) {
SG_LOG(SG_GENERAL, SG_ALERT, "(exceptionCount=" << exceptionCount << ", suspending)");
subsystem->suspend();
}
}
}