Compare commits

..

49 Commits

Author SHA1 Message Date
Jonathan Redpath
af0f7676c4 osgText: improve code to search aircraft directory for font 2022-01-12 11:16:05 +00:00
Automatic Release Builder
a3bdfab17b new version: 2020.3.12 2021-12-20 16:19:27 +00:00
Fernando García Liñán
44bae773a0 Canvas: Set pointers to NULL instead of calling .release()
The Canvas camera and texture get recreated in several circumstances.
Calling .release() on a ref_ptr will just return the raw pointer and
'delete' won't be called. The proper way to explicitly delete an object
managed by a ref_ptr is to set the ref_ptr to NULL. This will delete it
as long as it's not referenced by any other ref_ptr.
2021-12-20 16:12:06 +00:00
James Turner
5fe527a2d1 MaterialLib: make it thread-safe 2021-12-20 16:10:31 +00:00
James Turner
b79f03c96c Fix a ref-count loop in Paticles manager 2021-12-20 16:10:31 +00:00
Erik Hofman
631fa62495 Michael Danilov: Fix issue #2169 Sound with condition=false will play when moving into its max-dist (patch available) 2021-09-25 11:17:15 +02:00
Automatic Release Builder
a157e50302 Ooops, use correct variable name. 2021-07-29 10:21:20 +01:00
Automatic Release Builder
70e6b6b13f new version: 2020.3.11 2021-07-29 09:08:37 +01:00
James Turner
c457561472 HTTPRepo: Add detail to an error
This is showing up in the wild, but not clear how, so extend the
logging.
2021-07-29 08:47:12 +01:00
James Turner
2b5ac6350d remove an error on stable, too common. 2021-07-28 15:14:41 +01:00
James Turner
1c30b29168 Report errors on TileDetails callback failures
This callback can do out of memory and other failures, so catch
those and report them.
2021-07-28 15:14:41 +01:00
James Turner
ce9f476ddb Don't report PropsIO exceptions 2021-07-28 14:23:38 +01:00
James Turner
2621418d3a Fix a dumb back-port issue. 2021-07-22 10:11:04 +01:00
James Turner
174b341bef Don’t report HTTPRepo removeChild failures
Sentry-Id: FLIGHTGEAR-E5T
2021-07-15 10:31:28 +01:00
James Turner
df33713069 Remove incorrectly added ‘version’ file 2021-07-15 08:44:08 +01:00
James Turner
cde75530fe BTG reading: don’t crash on empty error message
Sentry-Id:FLIGHTGEAR-WA8
2021-07-15 08:43:31 +01:00
Automatic Release Builder
a9dddbcddc new version: 2020.3.10 2021-07-06 10:56:20 +01:00
James Turner
fcd72581a1 Make out-of-memory in computeHash fatal 2021-07-06 02:53:28 +01:00
James Turner
0a6091eeeb Error reporting for animations / conditions
Don’t report errors for each condition parse failure, but do 
aggregate them at the animation level in ReaderWriterXML

Sentry-Id: FLIGHTGEAR-DD
2021-07-06 02:50:11 +01:00
James Turner
d6400e3737 Add try/catch wrappers in SGSubsystemGroup
Attempt to narrow down the source of some fatal exceptions we see
on Senty, which occur during init/startup. All these blocks re-throw
so user behaviour is unchanged, but we’ll log the name of the subsytem.
2021-07-06 02:49:51 +01:00
James Turner
71e7050349 Attempt to fix realpath() recursion
Sentry-Id: FLIGHTGEAR-D6W
2021-06-15 17:31:33 +01:00
Automatic Release Builder
e6f4936536 better STG error reporting 2021-06-15 02:33:31 +01:00
Automatic Release Builder
b2ae7e9e63 Fix initial effect errors 2021-06-15 02:33:20 +01:00
Automatic Release Builder
ee0b22fd52 Fix HTTP repo erros 2021-06-15 02:33:11 +01:00
James Turner
01233ba537 Error-reporting: improve reports for STGs and effects
When an effect defines no shader sources, special case this error to
avoid confusing result from SGProgram.

Add error-context for readNode STG loading, so failures inside an
STG can be attributed
2021-06-14 20:01:30 +01:00
James Turner
ed29d9b75d Effects: better error reporting 2021-06-14 20:00:04 +01:00
James Turner
5d4201cdfa Shaders: report all shader file paths
When reporting a shader log error, include all the shader file
paths and the effect path in the detailed error information.
2021-06-14 19:59:36 +01:00
James Turner
2ef8c0d27b ReadWav: error reporting
Report errors from readWAV, and improve attribution for the
format error (include the file path). As a result, mark the individual
exceptions as dont-report, since we will report higher up.
2021-06-14 19:58:42 +01:00
James Turner
0fbfa3426f Catalogs: check for local IO failures writing to disk
Sentry.io shows some examples where we failed to write valid data
to disk; check for that if possible.
2021-06-14 19:58:18 +01:00
James Turner
57b4060eb3 Error-reporting: show XML path when 3D load fails 2021-06-14 19:57:16 +01:00
James Turner
84a569913d Report out-of-memory in some loading places
BTG can throw bad-alloc in the wild; catch this case and report it.
2021-06-14 19:56:53 +01:00
James Turner
b585df04a5 TerraSync: report errors during downloading
Report various out-of-memory and IO failure conditions; especially,
failure to write downloaded to disk, which was previously not 
recorded.
2021-06-14 19:55:07 +01:00
James Turner
ddba0c6731 Add osg::Program wrapper for error-reporting 2021-06-14 19:53:32 +01:00
James Turner
43d849232b ErrorReporting: set context for STG loading
Ensure the STG absolute path can be propagated to all files triggered
by STG loading, including the delayed files and proxied files. This
allows us to attribute errors to the correct scenery path.
2021-06-14 19:48:52 +01:00
James Turner
651460bbc8 Allow delayed setup of ErrorContext data
Permit no model data to be provided, when loading a model via the
modelLib API (d’oh)
2021-06-14 19:36:43 +01:00
James Turner
81a489d81d Error reporting: add SGModelData context support
Allow us to pass the current error-context from the main thread
into the osgDB loader thread. This is necessary so we can attribute
AIModel (etc) load problems to the correct source.
2021-06-14 19:36:25 +01:00
James Turner
7e76667af0 Error-reporting: add some errors for Effect shaders 2021-06-14 19:35:49 +01:00
James Turner
32f69df774 Error reporting for submodels
Also add some error codes I forgot for AI and traffic.
2021-06-14 19:34:55 +01:00
James Turner
d8d64b2367 Add failure reporting / context to various places.
Not total coverage by far, but working through the list of common
failure points as seen on Sentry
2021-06-14 19:34:28 +01:00
James Turner
747d99450b Suppress reports on some common exception throws 2021-06-14 19:27:26 +01:00
James Turner
b023c7c4f4 Add new error reporting function / callback 2021-06-14 19:23:54 +01:00
Erik Hofman
c19cf094a7 Backport the code to be able to display the region name of the file that holds the selected material. 2021-05-27 15:55:02 +02:00
Automatic Release Builder
279179e88d new version: 2020.3.9 2021-05-27 11:09:42 +01:00
James Turner
0ddd3e7f2f Add sg_location to all exceptions, add report flag
Move sg_location member up to the base clase, since it’s potentially
useful in more types.

Allow suppression of the report callback when the exception is thrown
2021-05-05 15:00:23 +01:00
James Turner
fe96298be5 Thread-safe error reporting in lowlevel.cxx
Use an exception rather than polling a flag, for checking errors
during BTG reading. This should allow us to give a correctly
identified error, at exactly the point the read fails.
2021-05-05 14:58:37 +01:00
James Turner
c6351292dd TerraSync: add a warning file to the root dir.
Try to discourage users from adding custom content underneath the
Terrasync dir, since it can be over-written.
2021-04-23 12:15:34 +01:00
James Turner
e2caad3b0b TerraSync: better reporting of permissions failures removing files
Log a ‘failed to remove orphan’ error as an error with the repository,
instead of failing the entire sync
2021-04-23 12:15:34 +01:00
James Turner
a095ab684c ASan: fix a leak in GZ extraction 2021-04-23 11:55:02 +01:00
James Turner
fe41a03180 Asan: fix leaks in Catalog code 2021-04-23 11:54:56 +01:00
51 changed files with 1536 additions and 905 deletions

View File

@@ -1 +1 @@
2020.3.8
2020.3.12

View File

@@ -298,8 +298,8 @@ namespace canvas
{
if( camera.valid() && Canvas::getSystemAdapter() )
Canvas::getSystemAdapter()->removeCamera(camera.get());
camera.release();
texture.release();
camera = nullptr;
texture = nullptr;
_flags &= ~AVAILABLE;
}

View File

@@ -17,11 +17,15 @@
#include "ErrorReportingCallback.hxx"
#include <simgear/misc/sg_path.hxx>
using std::string;
namespace simgear {
static ErrorReportCallback static_callback;
static ContextCallback static_contextCallback;
void setErrorReportCallback(ErrorReportCallback cb)
{
@@ -44,4 +48,73 @@ void reportFatalError(const std::string& msg, const std::string& more)
static_callback(msg, more, true);
}
static FailureCallback static_failureCallback;
void reportFailure(LoadFailure type, ErrorCode code, const std::string& details, sg_location loc)
{
if (!static_failureCallback) {
return;
}
static_failureCallback(type, code, details, loc);
}
void reportFailure(LoadFailure type, ErrorCode code, const std::string& details, const SGPath& path)
{
if (!static_failureCallback) {
return;
}
static_failureCallback(type, code, details, sg_location{path});
}
void setFailureCallback(FailureCallback cb)
{
static_failureCallback = cb;
}
void setErrorContextCallback(ContextCallback cb)
{
static_contextCallback = cb;
}
ErrorReportContext::ErrorReportContext(const std::string& key, const std::string& value)
{
add(key, value);
}
void ErrorReportContext::add(const std::string& key, const std::string& value)
{
if (static_contextCallback) {
_keys.push_back(key);
static_contextCallback(key, value);
}
}
ErrorReportContext::ErrorReportContext(const ContextMap& context)
{
addFromMap(context);
}
void ErrorReportContext::addFromMap(const ContextMap& context)
{
if (static_contextCallback) {
for (const auto& p : context) {
_keys.push_back(p.first);
static_contextCallback(p.first, p.second);
}
}
}
ErrorReportContext::~ErrorReportContext()
{
if (static_contextCallback) {
// pop all our keys
for (const auto& k : _keys) {
static_contextCallback(k, "POP");
}
}
}
} // namespace simgear

View File

@@ -16,7 +16,14 @@
#pragma once
#include <functional>
#include <map>
#include <string>
#include <vector>
#include <simgear/structure/exception.hxx>
//forward decls
class SGPath;
namespace simgear {
@@ -28,4 +35,94 @@ using ErrorReportCallback = std::function<void(const std::string& msg, const std
void setErrorReportCallback(ErrorReportCallback cb);
/** kinds of failures we can report. This is *how* (or why) something failed. Extend
as necessary but update the correponsdings string translations if you do. More detail isn't
necessariyl useful here: better to provide that in the 'details' string
*/
enum class LoadFailure {
Unknown,
NotFound,
OutOfMemory,
BadHeader,
BadData,
Misconfigured,
IOError, // disk full, permissions error, etc
NetworkError
};
/**
@brief enum of the operations which can fail. This should be extended as necessary: it maps to
translated error messages for the user. This describes what failed, the enum above gives why/how. The
combination of what+why should be something at the user level: use details for debug-level information.
*/
enum class ErrorCode {
LoadEffectsShaders,
LoadingTexture,
XMLModelLoad,
ThreeDModelLoad, // AC3D, OBJ, etc
BTGLoad,
ScenarioLoad,
GUIDialog,
AudioFX,
XMLLoadCommand,
AircraftSystems, // autopilot, hydrualics, instruments
InputDeviceConfig,
AITrafficSchedule,
TerraSync
};
/**
@brief Define an error-reporting context value, for the duration of this
object's lifetime. The context value will be active for any errors occuring on the same thread, while
this object exists.
*/
class ErrorReportContext
{
public:
ErrorReportContext(const std::string& key, const std::string& value);
using ContextMap = std::map<std::string, std::string>;
/**
Allow establishing multiple context values in a single operation
*/
ErrorReportContext(const ContextMap& context = {});
void add(const std::string& key, const std::string& value);
/**
@brief allowed delayed add of values
*/
void addFromMap(const ContextMap& context);
~ErrorReportContext();
private:
std::vector<std::string> _keys;
};
/**
* @brief Report failure to load a resource, so they can be collated for reporting
* to the user.
*
* @param type - the reason for the failure, if it can be determined
* @param msg - an informational message about what caused the failure
* @param path - path on disk to the resource. In some cases this may be a relative path;
* especially in the case of a resource not found, we cannot report a file path.
*/
void reportFailure(LoadFailure type, ErrorCode code, const std::string& detailedMessage = {}, sg_location loc = {});
/**
overload taking a path as the location
*/
void reportFailure(LoadFailure type, ErrorCode code, const std::string& detailedMessage, const SGPath& p);
using FailureCallback = std::function<void(LoadFailure type, ErrorCode code, const std::string& details, const sg_location& location)>;
void setFailureCallback(FailureCallback cb);
using ContextCallback = std::function<void(const std::string& key, const std::string& value)>;
void setErrorContextCallback(ContextCallback cb);
} // namespace simgear

View File

@@ -35,11 +35,12 @@
#include "simgear/debug/logstream.hxx"
#include "simgear/misc/strutils.hxx"
#include <simgear/misc/sg_dir.hxx>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/io/HTTPClient.hxx>
#include <simgear/io/iostreams/sgstream.hxx>
#include <simgear/io/sg_file.hxx>
#include <simgear/io/untar.hxx>
#include <simgear/io/iostreams/sgstream.hxx>
#include <simgear/misc/sg_dir.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/timing/timestamp.hxx>
@@ -218,8 +219,7 @@ public:
return;
}
char* buf = nullptr;
size_t bufSize = 0;
std::vector<char> buf;
for (auto& child : children) {
if (child.type != HTTPRepository::FileType)
@@ -240,17 +240,34 @@ public:
src.open(SG_IO_IN);
dst.open(SG_IO_OUT);
if (bufSize < cp.sizeInBytes()) {
bufSize = cp.sizeInBytes();
free(buf);
buf = (char*)malloc(bufSize);
if (!buf) {
continue;
const auto sizeToCopy = cp.sizeInBytes();
if (buf.size() < sizeToCopy) {
try {
buf.resize(sizeToCopy);
} catch (std::bad_alloc) {
simgear::reportFailure(simgear::LoadFailure::OutOfMemory, simgear::ErrorCode::TerraSync,
"copyInstalledChildren: couldn't allocation copy buffer of size:" + std::to_string(sizeToCopy),
child.path);
return;
}
}
src.read(buf, cp.sizeInBytes());
dst.write(buf, cp.sizeInBytes());
const auto r = src.read(buf.data(), sizeToCopy);
if (r != sizeToCopy) {
simgear::reportFailure(simgear::LoadFailure::IOError, simgear::ErrorCode::TerraSync,
"copyInstalledChildren: read underflow, got:" + std::to_string(r),
cp);
return;
}
const auto written = dst.write(buf.data(), sizeToCopy);
if (written != sizeToCopy) {
simgear::reportFailure(simgear::LoadFailure::IOError, simgear::ErrorCode::TerraSync,
"copyInstalledChildren: write underflow, wrote:" + std::to_string(r),
child.path);
return;
}
src.close();
dst.close();
@@ -260,9 +277,7 @@ public:
std::string hash = computeHashForPath(child.path);
updatedFileContents(child.path, hash);
}
free(buf);
}
}
/// helper to check and erase 'fooBar' from paths, if passed fooBar.zip, fooBar.tgz, etc.
@@ -377,7 +392,12 @@ public:
// We now have a list of entries that need to be updated, and a list
// of orphan files that should be removed.
removeOrphans(orphans);
try {
removeOrphans(orphans);
} catch (sg_exception& e) {
_repository->failedToUpdateChild(_relativePath, HTTPRepository::ResultCode::REPO_ERROR_IO);
}
scheduleUpdates(toBeUpdated);
}
@@ -389,11 +409,10 @@ public:
void removeOrphans(const PathList orphans)
{
PathList::const_iterator it;
for (it = orphans.begin(); it != orphans.end(); ++it) {
if (it->file() == ".dirindex") continue;
if (it->file() == ".hash") continue;
removeChild(*it);
for (const auto& o : orphans) {
if (o.file() == ".dirindex") continue;
if (o.file() == ".hash") continue;
removeChild(o);
}
}
@@ -755,7 +774,7 @@ private:
if (!ok) {
SG_LOG(SG_TERRASYNC, SG_WARN, "removal failed for:" << path);
throw sg_io_exception("Failed to remove existing file/dir:", path);
throw sg_io_exception("Failed to remove existing file/dir:", path, "", false);
}
}
@@ -1015,13 +1034,20 @@ HTTPRepository::failure() const
if (!file.get()) {
const bool ok = createOutputFile();
if (!ok) {
ioFailureOccurred = true;
_directory->repository()->http->cancelRequest(
this, "Unable to create output file:" + pathInRepo.utf8Str());
}
}
sha1_write(&hashContext, s, n);
file->write(s, n);
const auto written = file->write(s, n);
if (written != n) {
SG_LOG(SG_TERRASYNC, SG_WARN, "Underflow writing to " << pathInRepo);
ioFailureOccurred = true;
_directory->repository()->http->cancelRequest(
this, "Unable to write to output file:" + pathInRepo.utf8Str());
}
}
bool createOutputFile()
@@ -1078,8 +1104,15 @@ HTTPRepository::failure() const
void onFail() override {
HTTPRepository::ResultCode code = HTTPRepository::REPO_ERROR_SOCKET;
// -1 means request cancelled locally
if (responseCode() == -1) {
code = HTTPRepository::REPO_ERROR_CANCELLED;
if (ioFailureOccurred) {
// cancelled by code above due to IO error
code = HTTPRepository::REPO_ERROR_IO;
} else {
code = HTTPRepository::REPO_ERROR_CANCELLED;
}
}
if (file) {
@@ -1116,6 +1149,10 @@ HTTPRepository::failure() const
SGPath pathInRepo;
simgear::sha1nfo hashContext;
std::unique_ptr<SGBinaryFile> file;
/// becuase we cancel() in the case of an IO failure, we need to a way to distuinguish
/// user initated cancellation and IO-failure cancellation in onFail. This flag lets us do that
bool ioFailureOccurred = false;
};
class DirGetRequest : public HTTPRepoGetRequest
@@ -1369,6 +1406,9 @@ HTTPRepository::failure() const
if (st == HTTPRepository::REPO_ERROR_FILE_NOT_FOUND) {
status = HTTPRepository::REPO_ERROR_NOT_FOUND;
} else {
simgear::reportFailure(simgear::LoadFailure::NetworkError, simgear::ErrorCode::TerraSync,
"failed to get TerraSync repository root:" + innerResultCodeAsString(st),
sg_location{baseUrl});
SG_LOG(SG_TERRASYNC, SG_WARN, "Failed to get root of repo:" << baseUrl << " " << st);
status = st;
}
@@ -1384,7 +1424,12 @@ HTTPRepository::failure() const
SG_LOG(SG_TERRASYNC, SG_WARN,
"failed to update entry:" << relativePath << " status/code: "
<< innerResultCodeAsString(fileStatus)
<< "/" << fileStatus);
<< "/" << fileStatus
<< "\nrepo:" << baseUrl);
simgear::reportFailure(simgear::LoadFailure::NetworkError, simgear::ErrorCode::TerraSync,
"failed to update entry:" + innerResultCodeAsString(fileStatus),
sg_location{relativePath});
}
HTTPRepository::Failure f;

View File

@@ -23,28 +23,43 @@
// $Id$
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear_config.h>
#include <string.h> // for memcpy()
#include <errno.h>
#include "lowlevel.hxx"
#include <simgear/structure/exception.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/misc/sg_path.hxx>
#include "lowlevel.hxx"
static int read_error = false ;
static int write_error = false ;
thread_local SGPath thread_gzPath;
void sgClearReadError() { read_error = false; }
void sgClearWriteError() { write_error = false; }
int sgReadError() { return read_error ; }
int sgWriteError() { return write_error ; }
void setThreadLocalSimgearReadPath(const SGPath& path)
{
thread_gzPath = path;
}
static std::string gzErrorMessage(gzFile fd)
{
int errNum = 0;
const char *gzMsg = gzerror(fd, &errNum);
if (errNum == Z_ERRNO) {
return simgear::strutils::error_string(errno);
} else if (gzMsg) {
return {gzMsg};
}
return {"GZError: no string code for code:" + std::to_string(errNum)};
}
void sgReadChar ( gzFile fd, char *var )
{
if ( gzread ( fd, var, sizeof(char) ) != sizeof(char) ) {
read_error = true ;
throw sg_io_exception("sgReadChar: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
}
@@ -52,7 +67,7 @@ void sgReadChar ( gzFile fd, char *var )
void sgWriteChar ( gzFile fd, const char var )
{
if ( gzwrite ( fd, (void *)(&var), sizeof(char) ) != sizeof(char) ) {
write_error = true ;
throw sg_io_exception("sgWriteChar: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
@@ -61,7 +76,8 @@ void sgReadFloat ( gzFile fd, float *var )
{
union { float v; uint32_t u; } buf;
if ( gzread ( fd, &buf.u, sizeof(float) ) != sizeof(float) ) {
read_error = true ;
throw sg_io_exception("sgReadFloat: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
if ( sgIsBigEndian() ) {
sgEndianSwap( &buf.u );
@@ -78,7 +94,7 @@ void sgWriteFloat ( gzFile fd, const float var )
sgEndianSwap( &buf.u );
}
if ( gzwrite ( fd, (void *)(&buf.u), sizeof(float) ) != sizeof(float) ) {
write_error = true ;
throw sg_io_exception("sgWriteFloat: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
@@ -87,7 +103,8 @@ void sgReadDouble ( gzFile fd, double *var )
{
union { double v; uint64_t u; } buf;
if ( gzread ( fd, &buf.u, sizeof(double) ) != sizeof(double) ) {
read_error = true ;
throw sg_io_exception("sgReadDouble: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
if ( sgIsBigEndian() ) {
sgEndianSwap( &buf.u );
@@ -104,7 +121,7 @@ void sgWriteDouble ( gzFile fd, const double var )
sgEndianSwap( &buf.u );
}
if ( gzwrite ( fd, (void *)(&buf.u), sizeof(double) ) != sizeof(double) ) {
write_error = true ;
throw sg_io_exception("sgWriteDouble: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
@@ -112,7 +129,8 @@ void sgWriteDouble ( gzFile fd, const double var )
void sgReadUInt ( gzFile fd, unsigned int *var )
{
if ( gzread ( fd, var, sizeof(unsigned int) ) != sizeof(unsigned int) ) {
read_error = true ;
throw sg_io_exception("sgReadUInt: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
if ( sgIsBigEndian() ) {
sgEndianSwap( (uint32_t *)var);
@@ -128,7 +146,7 @@ void sgWriteUInt ( gzFile fd, const unsigned int var )
if ( gzwrite ( fd, (void *)(&var), sizeof(unsigned int) )
!= sizeof(unsigned int) )
{
write_error = true ;
throw sg_io_exception("sgWriteUInt: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
@@ -136,7 +154,8 @@ void sgWriteUInt ( gzFile fd, const unsigned int var )
void sgReadInt ( gzFile fd, int *var )
{
if ( gzread ( fd, var, sizeof(int) ) != sizeof(int) ) {
read_error = true ;
throw sg_io_exception("sgReadInt: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
if ( sgIsBigEndian() ) {
sgEndianSwap( (uint32_t *)var);
@@ -150,7 +169,7 @@ void sgWriteInt ( gzFile fd, const int var )
sgEndianSwap( (uint32_t *)&var);
}
if ( gzwrite ( fd, (void *)(&var), sizeof(int) ) != sizeof(int) ) {
write_error = true ;
throw sg_io_exception("sgWriteInt: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
@@ -158,7 +177,8 @@ void sgWriteInt ( gzFile fd, const int var )
void sgReadLong ( gzFile fd, int32_t *var )
{
if ( gzread ( fd, var, sizeof(int32_t) ) != sizeof(int32_t) ) {
read_error = true ;
throw sg_io_exception("sgReadLong: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
if ( sgIsBigEndian() ) {
sgEndianSwap( (uint32_t *)var);
@@ -174,7 +194,7 @@ void sgWriteLong ( gzFile fd, const int32_t var )
if ( gzwrite ( fd, (void *)(&var), sizeof(int32_t) )
!= sizeof(int32_t) )
{
write_error = true ;
throw sg_io_exception("sgWriteLong: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
@@ -182,7 +202,8 @@ void sgWriteLong ( gzFile fd, const int32_t var )
void sgReadLongLong ( gzFile fd, int64_t *var )
{
if ( gzread ( fd, var, sizeof(int64_t) ) != sizeof(int64_t) ) {
read_error = true ;
throw sg_io_exception("sgReadLongLong: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
if ( sgIsBigEndian() ) {
sgEndianSwap( (uint64_t *)var);
@@ -198,7 +219,7 @@ void sgWriteLongLong ( gzFile fd, const int64_t var )
if ( gzwrite ( fd, (void *)(&var), sizeof(int64_t) )
!= sizeof(int64_t) )
{
write_error = true ;
throw sg_io_exception("sgWriteLongLong: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
@@ -206,7 +227,8 @@ void sgWriteLongLong ( gzFile fd, const int64_t var )
void sgReadUShort ( gzFile fd, unsigned short *var )
{
if ( gzread ( fd, var, sizeof(unsigned short) ) != sizeof(unsigned short) ){
read_error = true ;
throw sg_io_exception("sgReadUShort: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
if ( sgIsBigEndian() ) {
sgEndianSwap( (uint16_t *)var);
@@ -222,7 +244,7 @@ void sgWriteUShort ( gzFile fd, const unsigned short var )
if ( gzwrite ( fd, (void *)(&var), sizeof(unsigned short) )
!= sizeof(unsigned short) )
{
write_error = true ;
throw sg_io_exception("sgWriteUShort: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
@@ -230,7 +252,8 @@ void sgWriteUShort ( gzFile fd, const unsigned short var )
void sgReadShort ( gzFile fd, short *var )
{
if ( gzread ( fd, var, sizeof(short) ) != sizeof(short) ) {
read_error = true ;
throw sg_io_exception("sgReadShort: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
if ( sgIsBigEndian() ) {
sgEndianSwap( (uint16_t *)var);
@@ -244,7 +267,7 @@ void sgWriteShort ( gzFile fd, const short var )
sgEndianSwap( (uint16_t *)&var);
}
if ( gzwrite ( fd, (void *)(&var), sizeof(short) ) != sizeof(short) ) {
write_error = true ;
throw sg_io_exception("sgWriteShort: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
@@ -252,7 +275,8 @@ void sgWriteShort ( gzFile fd, const short var )
void sgReadFloat ( gzFile fd, const unsigned int n, float *var )
{
if ( gzread ( fd, var, sizeof(float) * n ) != (int)(sizeof(float) * n) ) {
read_error = true ;
throw sg_io_exception("sgReadFloat array: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) {
@@ -276,14 +300,15 @@ void sgWriteFloat ( gzFile fd, const unsigned int n, const float *var )
if ( gzwrite ( fd, (void *)var, sizeof(float) * n )
!= (int)(sizeof(float) * n) )
{
write_error = true ;
throw sg_io_exception("sgWriteFloat array: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
void sgReadDouble ( gzFile fd, const unsigned int n, double *var )
{
if ( gzread ( fd, var, sizeof(double) * n ) != (int)(sizeof(double) * n) ) {
read_error = true ;
throw sg_io_exception("sgReadDouble array: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) {
@@ -307,7 +332,7 @@ void sgWriteDouble ( gzFile fd, const unsigned int n, const double *var )
if ( gzwrite ( fd, (void *)var, sizeof(double) * n )
!= (int)(sizeof(double) * n) )
{
write_error = true ;
throw sg_io_exception("sgWriteDouble array: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
@@ -315,7 +340,8 @@ void sgReadBytes ( gzFile fd, const unsigned int n, void *var )
{
if ( n == 0) return;
if ( gzread ( fd, var, n ) != (int)n ) {
read_error = true ;
throw sg_io_exception("sgReadBytes: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
}
@@ -323,7 +349,7 @@ void sgWriteBytes ( gzFile fd, const unsigned int n, const void *var )
{
if ( n == 0) return;
if ( gzwrite ( fd, (void *)var, n ) != (int)n ) {
write_error = true ;
throw sg_io_exception("sgWriteBytes: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
@@ -333,7 +359,8 @@ void sgReadUShort ( gzFile fd, const unsigned int n, unsigned short *var )
if ( gzread ( fd, var, sizeof(unsigned short) * n )
!= (int)(sizeof(unsigned short) * n) )
{
read_error = true ;
throw sg_io_exception("sgReadUShort array: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) {
@@ -357,7 +384,7 @@ void sgWriteUShort ( gzFile fd, const unsigned int n, const unsigned short *var
if ( gzwrite ( fd, (void *)var, sizeof(unsigned short) * n )
!= (int)(sizeof(unsigned short) * n) )
{
write_error = true ;
throw sg_io_exception("sgWriteUShort array: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
@@ -368,7 +395,8 @@ void sgReadShort ( gzFile fd, const unsigned int n, short *var )
if ( gzread ( fd, var, sizeof(short) * n )
!= (int)(sizeof(short) * n) )
{
read_error = true ;
throw sg_io_exception("sgReadShort array: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) {
@@ -392,7 +420,7 @@ void sgWriteShort ( gzFile fd, const unsigned int n, const short *var )
if ( gzwrite ( fd, (void *)var, sizeof(short) * n )
!= (int)(sizeof(short) * n) )
{
write_error = true ;
throw sg_io_exception("sgWriteShort array: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
@@ -402,7 +430,8 @@ void sgReadUInt ( gzFile fd, const unsigned int n, unsigned int *var )
if ( gzread ( fd, var, sizeof(unsigned int) * n )
!= (int)(sizeof(unsigned int) * n) )
{
read_error = true ;
throw sg_io_exception("sgReadUInt array: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) {
@@ -426,7 +455,7 @@ void sgWriteUInt ( gzFile fd, const unsigned int n, const unsigned int *var )
if ( gzwrite ( fd, (void *)var, sizeof(unsigned int) * n )
!= (int)(sizeof(unsigned int) * n) )
{
write_error = true ;
throw sg_io_exception("sgWriteUInt array: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}
@@ -437,7 +466,8 @@ void sgReadInt ( gzFile fd, const unsigned int n, int *var )
if ( gzread ( fd, var, sizeof(int) * n )
!= (int)(sizeof(int) * n) )
{
read_error = true ;
throw sg_io_exception("sgReadInt array: GZRead failed:" + gzErrorMessage(fd),
sg_location{thread_gzPath}, nullptr, false);
}
if ( sgIsBigEndian() ) {
for ( unsigned int i = 0; i < n; ++i ) {
@@ -461,7 +491,7 @@ void sgWriteInt ( gzFile fd, const unsigned int n, const int *var )
if ( gzwrite ( fd, (void *)var, sizeof(int) * n )
!= (int)(sizeof(int) * n) )
{
write_error = true ;
throw sg_io_exception("sgWriteInt array: gzwrite failed:" + gzErrorMessage(fd), {} /* origin */, false);
}
}

View File

@@ -35,6 +35,9 @@
#include <simgear/math/SGMath.hxx>
// forward decls
class SGPath;
// Note that output is written in little endian form (and converted as
// necessary for big endian machines)
@@ -121,9 +124,10 @@ inline void sgWriteGeod ( gzFile fd, const SGGeod& var ) {
sgWriteDouble( fd, var.getElevationM() );
}
void sgClearReadError();
void sgClearWriteError();
int sgReadError();
int sgWriteError();
/**
@ error aid: allow calling code to specify which file path we're reading from, so that erros we
throw from sgReadXXXX can have a valid location set.
*/
void setThreadLocalSimgearReadPath(const SGPath& path);
#endif // _SG_LOWLEVEL_HXX

View File

@@ -41,9 +41,10 @@
#include <bitset>
#include <simgear/bucket/newbucket.hxx>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/math/SGGeometry.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/math/SGGeometry.hxx>
#include <simgear/structure/exception.hxx>
#include "lowlevel.hxx"
@@ -454,10 +455,6 @@ void SGBinObject::read_object( gzFile fp,
}
}
if ( sgReadError() ) {
throw sg_exception("Error reading object properties");
}
size_t indexCount = std::bitset<32>((int)idx_mask).count();
if (indexCount == 0) {
throw sg_exception("object index mask has no bits set");
@@ -465,18 +462,10 @@ void SGBinObject::read_object( gzFile fp,
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
if ( sgReadError() ) {
throw sg_exception("Error reading element size");
}
buf.resize( nbytes );
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
if ( sgReadError() ) {
throw sg_exception("Error reading element bytes");
}
int_list vs;
int_list ns;
int_list cs;
@@ -503,314 +492,311 @@ void SGBinObject::read_object( gzFile fp,
// read a binary file and populate the provided structures.
bool SGBinObject::read_bin( const SGPath& file ) {
SGVec3d p;
int i, k;
size_t j;
unsigned int nbytes;
sgSimpleBuffer buf( 32768 ); // 32 Kb
bool SGBinObject::read_bin( const SGPath& file )
{
gzFile fp = NULL;
try {
SGVec3d p;
int i, k;
size_t j;
unsigned int nbytes;
sgSimpleBuffer buf( 32768 ); // 32 Kb
// zero out structures
gbs_center = SGVec3d(0, 0, 0);
gbs_radius = 0.0;
simgear::ErrorReportContext ec("btg", file.utf8Str());
wgs84_nodes.clear();
normals.clear();
texcoords.clear();
// zero out structures
gbs_center = SGVec3d(0, 0, 0);
gbs_radius = 0.0;
pts_v.clear();
pts_n.clear();
pts_c.clear();
pts_tcs.clear();
pts_vas.clear();
pt_materials.clear();
wgs84_nodes.clear();
normals.clear();
texcoords.clear();
tris_v.clear();
tris_n.clear();
tris_c.clear();
tris_tcs.clear();
tris_vas.clear();
tri_materials.clear();
pts_v.clear();
pts_n.clear();
pts_c.clear();
pts_tcs.clear();
pts_vas.clear();
pt_materials.clear();
strips_v.clear();
strips_n.clear();
strips_c.clear();
strips_tcs.clear();
strips_vas.clear();
strip_materials.clear();
tris_v.clear();
tris_n.clear();
tris_c.clear();
tris_tcs.clear();
tris_vas.clear();
tri_materials.clear();
fans_v.clear();
fans_n.clear();
fans_c.clear();
fans_tcs.clear();
fans_vas.clear();
fan_materials.clear();
strips_v.clear();
strips_n.clear();
strips_c.clear();
strips_tcs.clear();
strips_vas.clear();
strip_materials.clear();
gzFile fp = gzFileFromSGPath(file, "rb");
if ( fp == NULL ) {
SGPath withGZ = file;
withGZ.concat(".gz");
fp = gzFileFromSGPath(withGZ, "rb");
if (fp == nullptr) {
SG_LOG( SG_EVENT, SG_ALERT,
"ERROR: opening " << file << " or " << withGZ << " for reading!");
fans_v.clear();
fans_n.clear();
fans_c.clear();
fans_tcs.clear();
fans_vas.clear();
fan_materials.clear();
throw sg_io_exception("Error opening for reading (and .gz)", sg_location(file));
gzFile fp = gzFileFromSGPath(file, "rb");
if ( fp == NULL ) {
SGPath withGZ = file;
withGZ.concat(".gz");
fp = gzFileFromSGPath(withGZ, "rb");
if (fp == nullptr) {
throw sg_io_exception("Error opening for reading (and .gz)", sg_location(file), {}, false);
}
}
}
setThreadLocalSimgearReadPath(file);
sgClearReadError();
// read headers
unsigned int header;
sgReadUInt( fp, &header );
// read headers
unsigned int header;
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: " + string{gzErrorString} + ", code =" + std::to_string(code), sg_location(file));
}
if ( ((header & 0xFF000000) >> 24) == 'S' &&
((header & 0x00FF0000) >> 16) == 'G' ) {
if ( ((header & 0xFF000000) >> 24) == 'S' &&
((header & 0x00FF0000) >> 16) == 'G' ) {
// read file version
version = (header & 0x0000FFFF);
} else {
throw sg_io_exception("Bad BTG magic/version", sg_location(file), {}, false);
}
// read file version
version = (header & 0x0000FFFF);
} else {
// close the file before we return
gzclose(fp);
throw sg_io_exception("Bad BTG magic/version", sg_location(file));
}
// read creation time
unsigned int foo_calendar_time;
sgReadUInt( fp, &foo_calendar_time );
// read creation time
unsigned int foo_calendar_time;
sgReadUInt( fp, &foo_calendar_time );
#if 0
time_t calendar_time = foo_calendar_time;
// The following code has a global effect on the host application
// and can screws up the time elsewhere. It should be avoided
// unless you need this for debugging in which case you should
// disable it again once the debugging task is finished.
struct tm *local_tm;
local_tm = localtime( &calendar_time );
char time_str[256];
strftime( time_str, 256, "%a %b %d %H:%M:%S %Z %Y", local_tm);
SG_LOG( SG_EVENT, SG_DEBUG, "File created on " << time_str);
#endif
#if 0
time_t calendar_time = foo_calendar_time;
// The following code has a global effect on the host application
// and can screws up the time elsewhere. It should be avoided
// unless you need this for debugging in which case you should
// disable it again once the debugging task is finished.
struct tm *local_tm;
local_tm = localtime( &calendar_time );
char time_str[256];
strftime( time_str, 256, "%a %b %d %H:%M:%S %Z %Y", local_tm);
SG_LOG( SG_EVENT, SG_DEBUG, "File created on " << time_str);
#endif
// read number of top level objects
int nobjects;
if ( version >= 10) { // version 10 extends everything to be 32-bit
sgReadInt( fp, &nobjects );
} else if ( version >= 7 ) {
uint16_t v;
sgReadUShort( fp, &v );
nobjects = v;
} else {
int16_t v;
sgReadShort( fp, &v );
nobjects = v;
}
SG_LOG(SG_IO, SG_DEBUG, "SGBinObject::read_bin Total objects to read = " << nobjects);
if ( sgReadError() ) {
throw sg_io_exception("Error reading BTG file header", sg_location(file));
}
// read in objects
for ( i = 0; i < nobjects; ++i ) {
// read object header
char obj_type;
uint32_t nproperties, nelements;
sgReadChar( fp, &obj_type );
if ( version >= 10 ) {
sgReadUInt( fp, &nproperties );
sgReadUInt( fp, &nelements );
// read number of top level objects
int nobjects;
if ( version >= 10) { // version 10 extends everything to be 32-bit
sgReadInt( fp, &nobjects );
} else if ( version >= 7 ) {
uint16_t v;
sgReadUShort( fp, &v );
nproperties = v;
sgReadUShort( fp, &v );
nelements = v;
nobjects = v;
} else {
int16_t v;
sgReadShort( fp, &v );
nproperties = v;
sgReadShort( fp, &v );
nelements = v;
nobjects = v;
}
SG_LOG(SG_IO, SG_DEBUG, "SGBinObject::read_bin object " << i <<
" = " << (int)obj_type << " props = " << nproperties <<
" elements = " << nelements);
SG_LOG(SG_IO, SG_DEBUG, "SGBinObject::read_bin Total objects to read = " << nobjects);
if ( obj_type == SG_BOUNDING_SPHERE ) {
// read bounding sphere properties
read_properties( fp, nproperties );
// read bounding sphere elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
buf.resize( nbytes );
buf.reset();
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
gbs_center = buf.readVec3d();
gbs_radius = buf.readFloat();
// read in objects
for ( i = 0; i < nobjects; ++i ) {
// read object header
char obj_type;
uint32_t nproperties, nelements;
sgReadChar( fp, &obj_type );
if ( version >= 10 ) {
sgReadUInt( fp, &nproperties );
sgReadUInt( fp, &nelements );
} else if ( version >= 7 ) {
uint16_t v;
sgReadUShort( fp, &v );
nproperties = v;
sgReadUShort( fp, &v );
nelements = v;
} else {
int16_t v;
sgReadShort( fp, &v );
nproperties = v;
sgReadShort( fp, &v );
nelements = v;
}
} else if ( obj_type == SG_VERTEX_LIST ) {
// read vertex list properties
read_properties( fp, nproperties );
// read vertex list elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
buf.resize( nbytes );
buf.reset();
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
int count = nbytes / (sizeof(float) * 3);
wgs84_nodes.reserve( count );
for ( k = 0; k < count; ++k ) {
SGVec3f v = buf.readVec3f();
// extend from float to double, hmmm
wgs84_nodes.push_back( SGVec3d(v[0], v[1], v[2]) );
SG_LOG(SG_IO, SG_DEBUG, "SGBinObject::read_bin object " << i <<
" = " << (int)obj_type << " props = " << nproperties <<
" elements = " << nelements);
if ( obj_type == SG_BOUNDING_SPHERE ) {
// read bounding sphere properties
read_properties( fp, nproperties );
// read bounding sphere elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
buf.resize( nbytes );
buf.reset();
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
gbs_center = buf.readVec3d();
gbs_radius = buf.readFloat();
}
}
} else if ( obj_type == SG_COLOR_LIST ) {
// read color list properties
read_properties( fp, nproperties );
} else if ( obj_type == SG_VERTEX_LIST ) {
// read vertex list properties
read_properties( fp, nproperties );
// read color list elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
buf.resize( nbytes );
buf.reset();
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
int count = nbytes / (sizeof(float) * 4);
colors.reserve(count);
for ( k = 0; k < count; ++k ) {
colors.push_back( buf.readVec4f() );
// read vertex list elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
buf.resize( nbytes );
buf.reset();
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
int count = nbytes / (sizeof(float) * 3);
wgs84_nodes.reserve( count );
for ( k = 0; k < count; ++k ) {
SGVec3f v = buf.readVec3f();
// extend from float to double, hmmm
wgs84_nodes.push_back( SGVec3d(v[0], v[1], v[2]) );
}
}
}
} else if ( obj_type == SG_NORMAL_LIST ) {
// read normal list properties
read_properties( fp, nproperties );
} else if ( obj_type == SG_COLOR_LIST ) {
// read color list properties
read_properties( fp, nproperties );
// read normal list elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
buf.resize( nbytes );
buf.reset();
unsigned char *ptr = (unsigned char *)(buf.get_ptr());
sgReadBytes( fp, nbytes, ptr );
int count = nbytes / 3;
normals.reserve( count );
for ( k = 0; k < count; ++k ) {
SGVec3f normal( (ptr[0]) / 127.5 - 1.0,
(ptr[1]) / 127.5 - 1.0,
(ptr[2]) / 127.5 - 1.0);
normals.push_back(normalize(normal));
ptr += 3;
// read color list elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
buf.resize( nbytes );
buf.reset();
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
int count = nbytes / (sizeof(float) * 4);
colors.reserve(count);
for ( k = 0; k < count; ++k ) {
colors.push_back( buf.readVec4f() );
}
}
}
} else if ( obj_type == SG_TEXCOORD_LIST ) {
// read texcoord list properties
read_properties( fp, nproperties );
} else if ( obj_type == SG_NORMAL_LIST ) {
// read normal list properties
read_properties( fp, nproperties );
// read texcoord list elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
buf.resize( nbytes );
buf.reset();
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
int count = nbytes / (sizeof(float) * 2);
texcoords.reserve(count);
for ( k = 0; k < count; ++k ) {
texcoords.push_back( buf.readVec2f() );
// read normal list elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
buf.resize( nbytes );
buf.reset();
unsigned char *ptr = (unsigned char *)(buf.get_ptr());
sgReadBytes( fp, nbytes, ptr );
int count = nbytes / 3;
normals.reserve( count );
for ( k = 0; k < count; ++k ) {
SGVec3f normal( (ptr[0]) / 127.5 - 1.0,
(ptr[1]) / 127.5 - 1.0,
(ptr[2]) / 127.5 - 1.0);
normals.push_back(normalize(normal));
ptr += 3;
}
}
}
} else if ( obj_type == SG_VA_FLOAT_LIST ) {
// read vertex attribute (float) properties
read_properties( fp, nproperties );
} else if ( obj_type == SG_TEXCOORD_LIST ) {
// read texcoord list properties
read_properties( fp, nproperties );
// read vertex attribute list elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
buf.resize( nbytes );
buf.reset();
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
int count = nbytes / (sizeof(float));
va_flt.reserve(count);
for ( k = 0; k < count; ++k ) {
va_flt.push_back( buf.readFloat() );
// read texcoord list elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
buf.resize( nbytes );
buf.reset();
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
int count = nbytes / (sizeof(float) * 2);
texcoords.reserve(count);
for ( k = 0; k < count; ++k ) {
texcoords.push_back( buf.readVec2f() );
}
}
}
} else if ( obj_type == SG_VA_INTEGER_LIST ) {
// read vertex attribute (integer) properties
read_properties( fp, nproperties );
} else if ( obj_type == SG_VA_FLOAT_LIST ) {
// read vertex attribute (float) properties
read_properties( fp, nproperties );
// read vertex attribute list elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
buf.resize( nbytes );
buf.reset();
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
int count = nbytes / (sizeof(unsigned int));
va_int.reserve(count);
for ( k = 0; k < count; ++k ) {
va_int.push_back( buf.readInt() );
// read vertex attribute list elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
buf.resize( nbytes );
buf.reset();
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
int count = nbytes / (sizeof(float));
va_flt.reserve(count);
for ( k = 0; k < count; ++k ) {
va_flt.push_back( buf.readFloat() );
}
}
}
} else if ( obj_type == SG_POINTS ) {
// read point elements
read_object( fp, SG_POINTS, nproperties, nelements,
pts_v, pts_n, pts_c, pts_tcs,
pts_vas, pt_materials );
} else if ( obj_type == SG_TRIANGLE_FACES ) {
// read triangle face properties
read_object( fp, SG_TRIANGLE_FACES, nproperties, nelements,
tris_v, tris_n, tris_c, tris_tcs,
tris_vas, tri_materials );
} else if ( obj_type == SG_TRIANGLE_STRIPS ) {
// read triangle strip properties
read_object( fp, SG_TRIANGLE_STRIPS, nproperties, nelements,
strips_v, strips_n, strips_c, strips_tcs,
strips_vas, strip_materials );
} else if ( obj_type == SG_TRIANGLE_FANS ) {
// read triangle fan properties
read_object( fp, SG_TRIANGLE_FANS, nproperties, nelements,
fans_v, fans_n, fans_c, fans_tcs,
fans_vas, fan_materials );
} else {
// unknown object type, just skip
read_properties( fp, nproperties );
} else if ( obj_type == SG_VA_INTEGER_LIST ) {
// read vertex attribute (integer) properties
read_properties( fp, nproperties );
// read elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
// cout << "element size = " << nbytes << endl;
if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
// read vertex attribute list elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
buf.resize( nbytes );
buf.reset();
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
int count = nbytes / (sizeof(unsigned int));
va_int.reserve(count);
for ( k = 0; k < count; ++k ) {
va_int.push_back( buf.readInt() );
}
}
} else if ( obj_type == SG_POINTS ) {
// read point elements
read_object( fp, SG_POINTS, nproperties, nelements,
pts_v, pts_n, pts_c, pts_tcs,
pts_vas, pt_materials );
} else if ( obj_type == SG_TRIANGLE_FACES ) {
// read triangle face properties
read_object( fp, SG_TRIANGLE_FACES, nproperties, nelements,
tris_v, tris_n, tris_c, tris_tcs,
tris_vas, tri_materials );
} else if ( obj_type == SG_TRIANGLE_STRIPS ) {
// read triangle strip properties
read_object( fp, SG_TRIANGLE_STRIPS, nproperties, nelements,
strips_v, strips_n, strips_c, strips_tcs,
strips_vas, strip_materials );
} else if ( obj_type == SG_TRIANGLE_FANS ) {
// read triangle fan properties
read_object( fp, SG_TRIANGLE_FANS, nproperties, nelements,
fans_v, fans_n, fans_c, fans_tcs,
fans_vas, fan_materials );
} else {
// unknown object type, just skip
read_properties( fp, nproperties );
// read elements
for ( j = 0; j < nelements; ++j ) {
sgReadUInt( fp, &nbytes );
// cout << "element size = " << nbytes << endl;
if ( nbytes > buf.get_size() ) { buf.resize( nbytes ); }
char *ptr = buf.get_ptr();
sgReadBytes( fp, nbytes, ptr );
}
}
}
if ( sgReadError() ) {
throw sg_io_exception("Error while reading object", sg_location(file, i));
gzclose(fp);
fp = NULL;
} catch (std::exception&) {
if (fp) {
// close the file
gzclose(fp);
}
throw; // re-throw
}
// close the file
gzclose(fp);
return true;
}
@@ -984,112 +970,112 @@ bool SGBinObject::write_bin_file(const SGPath& file)
return false;
}
sgClearWriteError();
try {
SG_LOG(SG_IO, SG_DEBUG, "points size = " << pts_v.size()
<< " pt_materials = " << pt_materials.size() );
SG_LOG(SG_IO, SG_DEBUG, "triangles size = " << tris_v.size()
<< " tri_materials = " << tri_materials.size() );
SG_LOG(SG_IO, SG_DEBUG, "strips size = " << strips_v.size()
<< " strip_materials = " << strip_materials.size() );
SG_LOG(SG_IO, SG_DEBUG, "fans size = " << fans_v.size()
<< " fan_materials = " << fan_materials.size() );
SG_LOG(SG_IO, SG_DEBUG, "points size = " << pts_v.size()
<< " pt_materials = " << pt_materials.size() );
SG_LOG(SG_IO, SG_DEBUG, "triangles size = " << tris_v.size()
<< " tri_materials = " << tri_materials.size() );
SG_LOG(SG_IO, SG_DEBUG, "strips size = " << strips_v.size()
<< " strip_materials = " << strip_materials.size() );
SG_LOG(SG_IO, SG_DEBUG, "fans size = " << fans_v.size()
<< " fan_materials = " << fan_materials.size() );
SG_LOG(SG_IO, SG_DEBUG, "nodes = " << wgs84_nodes.size() );
SG_LOG(SG_IO, SG_DEBUG, "colors = " << colors.size() );
SG_LOG(SG_IO, SG_DEBUG, "normals = " << normals.size() );
SG_LOG(SG_IO, SG_DEBUG, "tex coords = " << texcoords.size() );
SG_LOG(SG_IO, SG_DEBUG, "nodes = " << wgs84_nodes.size() );
SG_LOG(SG_IO, SG_DEBUG, "colors = " << colors.size() );
SG_LOG(SG_IO, SG_DEBUG, "normals = " << normals.size() );
SG_LOG(SG_IO, SG_DEBUG, "tex coords = " << texcoords.size() );
version = 10;
bool shortMaterialsRanges =
(max_object_size(pt_materials) < VERSION_7_MATERIAL_LIMIT) &&
(max_object_size(fan_materials) < VERSION_7_MATERIAL_LIMIT) &&
(max_object_size(strip_materials) < VERSION_7_MATERIAL_LIMIT) &&
(max_object_size(tri_materials) < VERSION_7_MATERIAL_LIMIT);
version = 10;
bool shortMaterialsRanges =
(max_object_size(pt_materials) < VERSION_7_MATERIAL_LIMIT) &&
(max_object_size(fan_materials) < VERSION_7_MATERIAL_LIMIT) &&
(max_object_size(strip_materials) < VERSION_7_MATERIAL_LIMIT) &&
(max_object_size(tri_materials) < VERSION_7_MATERIAL_LIMIT);
if ((wgs84_nodes.size() < 0xffff) &&
(normals.size() < 0xffff) &&
(texcoords.size() < 0xffff) &&
shortMaterialsRanges) {
version = 7; // use smaller indices if possible
}
if ((wgs84_nodes.size() < 0xffff) &&
(normals.size() < 0xffff) &&
(texcoords.size() < 0xffff) &&
shortMaterialsRanges) {
version = 7; // use smaller indices if possible
}
// write header magic
// write header magic
/** Magic Number for our file format */
#define SG_FILE_MAGIC_NUMBER ( ('S'<<24) + ('G'<<16) + version )
/** Magic Number for our file format */
#define SG_FILE_MAGIC_NUMBER ( ('S'<<24) + ('G'<<16) + version )
sgWriteUInt( fp, SG_FILE_MAGIC_NUMBER );
time_t calendar_time = time(NULL);
sgWriteLong( fp, (int32_t)calendar_time );
sgWriteUInt( fp, SG_FILE_MAGIC_NUMBER );
time_t calendar_time = time(NULL);
sgWriteLong( fp, (int32_t)calendar_time );
// calculate and write number of top level objects
int nobjects = 5; // gbs, vertices, colors, normals, texcoords
nobjects += count_objects(pt_materials);
nobjects += count_objects(tri_materials);
nobjects += count_objects(strip_materials);
nobjects += count_objects(fan_materials);
// calculate and write number of top level objects
int nobjects = 5; // gbs, vertices, colors, normals, texcoords
nobjects += count_objects(pt_materials);
nobjects += count_objects(tri_materials);
nobjects += count_objects(strip_materials);
nobjects += count_objects(fan_materials);
SG_LOG(SG_IO, SG_DEBUG, "total top level objects = " << nobjects);
SG_LOG(SG_IO, SG_DEBUG, "total top level objects = " << nobjects);
if (version == 7) {
sgWriteUShort( fp, (uint16_t) nobjects );
} else {
sgWriteInt( fp, nobjects );
}
if (version == 7) {
sgWriteUShort( fp, (uint16_t) nobjects );
} else {
sgWriteInt( fp, nobjects );
}
// write bounding sphere
write_header( fp, SG_BOUNDING_SPHERE, 0, 1);
sgWriteUInt( fp, sizeof(double) * 3 + sizeof(float) ); // nbytes
sgWritedVec3( fp, gbs_center );
sgWriteFloat( fp, gbs_radius );
// write bounding sphere
write_header( fp, SG_BOUNDING_SPHERE, 0, 1);
sgWriteUInt( fp, sizeof(double) * 3 + sizeof(float) ); // nbytes
sgWritedVec3( fp, gbs_center );
sgWriteFloat( fp, gbs_radius );
// dump vertex list
write_header( fp, SG_VERTEX_LIST, 0, 1);
sgWriteUInt( fp, wgs84_nodes.size() * sizeof(float) * 3 ); // nbytes
for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) {
sgWriteVec3( fp, toVec3f(wgs84_nodes[i] - gbs_center));
}
// dump vertex list
write_header( fp, SG_VERTEX_LIST, 0, 1);
sgWriteUInt( fp, wgs84_nodes.size() * sizeof(float) * 3 ); // nbytes
for ( i = 0; i < (int)wgs84_nodes.size(); ++i ) {
sgWriteVec3( fp, toVec3f(wgs84_nodes[i] - gbs_center));
}
// dump vertex color list
write_header( fp, SG_COLOR_LIST, 0, 1);
sgWriteUInt( fp, colors.size() * sizeof(float) * 4 ); // nbytes
for ( i = 0; i < (int)colors.size(); ++i ) {
sgWriteVec4( fp, colors[i]);
}
// dump vertex color list
write_header( fp, SG_COLOR_LIST, 0, 1);
sgWriteUInt( fp, colors.size() * sizeof(float) * 4 ); // nbytes
for ( i = 0; i < (int)colors.size(); ++i ) {
sgWriteVec4( fp, colors[i]);
}
// dump vertex normal list
write_header( fp, SG_NORMAL_LIST, 0, 1);
sgWriteUInt( fp, normals.size() * 3 ); // nbytes
char normal[3];
for ( i = 0; i < (int)normals.size(); ++i ) {
SGVec3f p = normals[i];
normal[0] = (unsigned char)((p.x() + 1.0) * 127.5);
normal[1] = (unsigned char)((p.y() + 1.0) * 127.5);
normal[2] = (unsigned char)((p.z() + 1.0) * 127.5);
sgWriteBytes( fp, 3, normal );
}
// dump vertex normal list
write_header( fp, SG_NORMAL_LIST, 0, 1);
sgWriteUInt( fp, normals.size() * 3 ); // nbytes
char normal[3];
for ( i = 0; i < (int)normals.size(); ++i ) {
SGVec3f p = normals[i];
normal[0] = (unsigned char)((p.x() + 1.0) * 127.5);
normal[1] = (unsigned char)((p.y() + 1.0) * 127.5);
normal[2] = (unsigned char)((p.z() + 1.0) * 127.5);
sgWriteBytes( fp, 3, normal );
}
// dump texture coordinates
write_header( fp, SG_TEXCOORD_LIST, 0, 1);
sgWriteUInt( fp, texcoords.size() * sizeof(float) * 2 ); // nbytes
for ( i = 0; i < (int)texcoords.size(); ++i ) {
sgWriteVec2( fp, texcoords[i]);
}
// dump texture coordinates
write_header( fp, SG_TEXCOORD_LIST, 0, 1);
sgWriteUInt( fp, texcoords.size() * sizeof(float) * 2 ); // nbytes
for ( i = 0; i < (int)texcoords.size(); ++i ) {
sgWriteVec2( fp, texcoords[i]);
}
write_objects(fp, SG_POINTS, pts_v, pts_n, pts_c, pts_tcs, pts_vas, pt_materials);
write_objects(fp, SG_TRIANGLE_FACES, tris_v, tris_n, tris_c, tris_tcs, tris_vas, tri_materials);
write_objects(fp, SG_TRIANGLE_STRIPS, strips_v, strips_n, strips_c, strips_tcs, strips_vas, strip_materials);
write_objects(fp, SG_TRIANGLE_FANS, fans_v, fans_n, fans_c, fans_tcs, fans_vas, fan_materials);
write_objects(fp, SG_POINTS, pts_v, pts_n, pts_c, pts_tcs, pts_vas, pt_materials);
write_objects(fp, SG_TRIANGLE_FACES, tris_v, tris_n, tris_c, tris_tcs, tris_vas, tri_materials);
write_objects(fp, SG_TRIANGLE_STRIPS, strips_v, strips_n, strips_c, strips_tcs, strips_vas, strip_materials);
write_objects(fp, SG_TRIANGLE_FANS, fans_v, fans_n, fans_c, fans_tcs, fans_vas, fan_materials);
// close the file
gzclose(fp);
if ( sgWriteError() ) {
cout << "Error while writing file " << file << endl;
// close the file
gzclose(fp);
fp = NULL;
} catch (std::exception&) {
if (fp) {
gzclose(fp);
}
return false;
}
return true;
}

View File

@@ -82,9 +82,7 @@ std::string SGFile::computeHash()
[](char* p) { free(p); }};
if (!buf) {
// @TODO report out of memory error
SG_LOG(SG_IO, SG_ALERT, "Failed to malloc buffer for SHA1 check:" << file_name);
return {};
throw sg_exception("Malloc of SHA buffer failed", {}, file_name);
}
size_t readLen;

View File

@@ -348,6 +348,9 @@ public:
~GZTarExtractor()
{
if (haveInitedZLib) {
inflateEnd(&zlibStream);
}
free(zlibOutput);
}

View File

@@ -48,6 +48,7 @@
#endif
#include "sg_path.hxx"
#include <simgear/misc/sg_dir.hxx>
using std::string;
using simgear::strutils::starts_with;
@@ -995,8 +996,9 @@ SGPath SGPath::realpath() const
// (needed for fgValidatePath security)
{
if (path.empty()) {
return SGPath(".").realpath(); // current directory
return simgear::Dir::current().path();
}
std::string this_dir = dir();
if (isAbsolute() && this_dir.empty()) { // top level
this_dir = "/";

View File

@@ -143,9 +143,15 @@ protected:
Dir d(m_owner->installRoot());
SGPath p = d.file("catalog.xml");
sg_ofstream f(p, std::ios::out | std::ios::trunc);
f.write(m_buffer.data(), m_buffer.size());
const auto sz = m_buffer.size();
f.write(m_buffer.data(), sz);
f.close();
if (f.fail()) {
m_owner->refreshComplete(Delegate::FAIL_FILESYSTEM);
return;
}
time(&m_owner->m_retrievedTime);
m_owner->writeTimestamp();
m_owner->refreshComplete(Delegate::STATUS_REFRESHED);
@@ -619,6 +625,8 @@ void Catalog::setUserEnabled(bool b)
void Catalog::processAlternate(SGPropertyNode_ptr alt)
{
m_refreshRequest.reset();
std::string altId;
const auto idPtr = alt->getStringValue("id");
if (idPtr) {
@@ -694,8 +702,8 @@ void Catalog::processAlternate(SGPropertyNode_ptr alt)
SG_LOG(SG_GENERAL, SG_INFO, "Migrating catalog " << id() << " to new URL:" << altUrl);
setUrl(altUrl);
Downloader* dl = new Downloader(this, altUrl);
root()->makeHTTPRequest(dl);
m_refreshRequest = new Downloader(this, altUrl);
root()->makeHTTPRequest(m_refreshRequest);
}
int Catalog::markPackagesForInstallation(const string_list &packageIds) {

View File

@@ -166,7 +166,8 @@ int parseTest()
{
SGPath rootPath = simgear::Dir::current().path();
rootPath.append("testRoot");
pkg::Root* root = new pkg::Root(rootPath, "8.1.12");
pkg::RootRef root(new pkg::Root(rootPath, "8.1.2"));
root->setLocale("de");
pkg::CatalogRef cat = pkg::Catalog::createFromPath(root, SGPath(SRC_DIR "/catalogTest1"));
@@ -344,7 +345,6 @@ int parseTest()
SG_CHECK_EQUAL(urls.size(), 3);
SG_CHECK_EQUAL(urls.at(1), "http://localhost:2000/mirrorB/b737.tar.gz");
delete root;
return EXIT_SUCCESS;
}
@@ -953,7 +953,7 @@ int parseInvalidTest()
{
SGPath rootPath = simgear::Dir::current().path();
rootPath.append("testRoot");
pkg::Root* root = new pkg::Root(rootPath, "8.1.12");
pkg::RootRef root(new pkg::Root(rootPath, "8.1.12"));
pkg::CatalogRef cat = pkg::Catalog::createFromPath(root, SGPath(SRC_DIR "/catalogTestInvalid"));
SG_VERIFY(cat.valid());
@@ -1333,25 +1333,25 @@ int main(int argc, char* argv[])
testRefreshCatalog(&cl);
testInstallTarPackage(&cl);
testInstallArchiveType(&cl);
testDisableDueToVersion(&cl);
testOfflineMode(&cl);
testVersionMigrate(&cl);
updateInvalidToValid(&cl);
updateValidToInvalid(&cl);
updateInvalidToInvalid(&cl);
removeInvalidCatalog(&cl);
testVersionMigrateToId(&cl);
testInstallBadPackage(&cl);
testMirrorsFailure(&cl);
testMigrateInstalled(&cl);

View File

@@ -535,7 +535,8 @@ readComparison( SGPropertyNode *prop_root,
{
SGComparisonCondition * condition = new SGComparisonCondition(type, reverse);
if (node->nChildren() < 2 || node->nChildren() > 3 ) {
throw sg_exception("condition: comparison without two or three children");
throw sg_exception("condition: comparison without two or three children",
{}, {}, false);
}
const SGPropertyNode* left = node->getChild(0),
@@ -551,7 +552,8 @@ readComparison( SGPropertyNode *prop_root,
SGExpressiond* exp = SGReadDoubleExpression(prop_root, left->getChild(0));
condition->setLeftDExpression(exp);
} else {
throw sg_exception("Unknown condition comparison left child:" + leftName);
throw sg_exception("Unknown condition comparison left child:" + leftName,
{}, {}, false);
}
}
@@ -565,7 +567,8 @@ readComparison( SGPropertyNode *prop_root,
SGExpressiond* exp = SGReadDoubleExpression(prop_root, right->getChild(0));
condition->setRightDExpression(exp);
} else {
throw sg_exception("Unknown condition comparison right child:" + rightName);
throw sg_exception("Unknown condition comparison right child:" + rightName,
{}, {}, false);
}
}
@@ -580,7 +583,8 @@ readComparison( SGPropertyNode *prop_root,
SGExpressiond* exp = SGReadDoubleExpression(prop_root, n->getChild(0));
condition->setPrecisionDExpression(exp);
} else {
throw sg_exception("Unknown condition comparison precision child:" + name );
throw sg_exception("Unknown condition comparison precision child:" + name,
{}, {}, false);
}
}

View File

@@ -161,7 +161,7 @@ setFlag( int& mode,
string message = "Unrecognized flag value '";
message += flag;
message += '\'';
throw sg_io_exception(message, location, SG_ORIGIN);
throw sg_io_exception(message, location, SG_ORIGIN, false);
}
}
@@ -176,7 +176,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
string message = "Root element name is ";
message += name;
message += "; expected PropertyList";
throw sg_io_exception(message, location, SG_ORIGIN);
throw sg_io_exception(message, location, SG_ORIGIN, false);
}
// Check for an include.
@@ -188,7 +188,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
{
string message ="Cannot open file ";
message += attval;
throw sg_io_exception(message, location, SG_ORIGIN);
throw sg_io_exception(message, location, SG_ORIGIN, false);
}
readProperties(path, _root, 0, _extended);
} catch (sg_io_exception &e) {
@@ -278,7 +278,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
{
string message ="Cannot open file ";
message += val;
throw sg_io_exception(message, location, SG_ORIGIN);
throw sg_io_exception(message, location, SG_ORIGIN, false);
}
readProperties(path, node, 0, _extended);
}
@@ -353,7 +353,7 @@ PropsVisitor::endElement (const char * name)
string message = "Unrecognized data type '";
message += st.type;
message += '\'';
throw sg_io_exception(message, location, SG_ORIGIN);
throw sg_io_exception(message, location, SG_ORIGIN, false);
}
if( !ret )
SG_LOG
@@ -701,7 +701,7 @@ writeProperties (const SGPath &path, const SGPropertyNode * start_node,
if (output.good()) {
writeProperties(output, start_node, write_all, archive_flag);
} else {
throw sg_io_exception("Cannot open file", sg_location(path.utf8Str()));
throw sg_io_exception("Cannot open file", sg_location(path.utf8Str()), "", false);
}
}
@@ -770,7 +770,7 @@ copyPropertyValue(const SGPropertyNode *in, SGPropertyNode *out)
break;
string message = "Unknown internal SGPropertyNode type";
message += in->getType();
throw sg_error(message, SG_ORIGIN);
throw sg_error(message, SG_ORIGIN, false);
}
return retval;

View File

@@ -67,9 +67,14 @@
#include <osgDB/ReadFile>
#include <osgDB/Registry>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/io/iostreams/sgstream.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/props/vectorPropTemplates.hxx>
#include <simgear/scene/tgdb/userdata.hxx>
#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/util/SGProgram.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/scene/util/SGSceneFeatures.hxx>
#include <simgear/scene/util/StateAttributeFactory.hxx>
#include <simgear/structure/OSGUtils.hxx>
@@ -103,6 +108,7 @@ bool loadShaderFromUTF8File(osg::Shader* shader, const std::string& fileName)
if (!inStream.is_open())
return false;
shader->setFileName(fileName);
shader->setShaderSource(inStream.read_all());
return true;
}
@@ -221,8 +227,9 @@ Effect::Effect()
}
Effect::Effect(const Effect& rhs, const CopyOp& copyop)
: osg::Object(rhs,copyop), root(rhs.root), parametersProp(rhs.parametersProp), _cache(0),
_isRealized(rhs._isRealized)
: osg::Object(rhs, copyop), root(rhs.root), parametersProp(rhs.parametersProp), _cache(0),
_isRealized(rhs._isRealized),
_effectFilePath(rhs._effectFilePath)
{
typedef vector<ref_ptr<Technique> > TechniqueList;
for (TechniqueList::const_iterator itr = rhs.techniques.begin(),
@@ -287,6 +294,8 @@ Effect::~Effect()
void buildPass(Effect* effect, Technique* tniq, const SGPropertyNode* prop,
const SGReaderWriterOptions* options)
{
simgear::ErrorReportContext ec("effect-pass", prop->getPath());
Pass* pass = new Pass;
tniq->passes.push_back(pass);
for (int i = 0; i < prop->nChildren(); ++i) {
@@ -837,10 +846,12 @@ void reload_shaders()
string fileName = SGModelLib::findDataFile(sitr->first.first);
if (!fileName.empty()) {
loadShaderFromUTF8File(shader, fileName);
}
else
} else {
SG_LOG(SG_INPUT, SG_ALERT, "Could not locate shader: " << fileName);
simgear::reportFailure(simgear::LoadFailure::NotFound,
simgear::ErrorCode::LoadEffectsShaders,
"Reload: couldn't find shader:" + sitr->first.first);
}
}
}
@@ -936,10 +947,8 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
string fileName = SGModelLib::findDataFile(shaderName, options);
if (fileName.empty())
{
SG_LOG(SG_INPUT, SG_ALERT, "Could not locate shader" << shaderName);
if (!compositorEnabled) {
reportError("Missing shader", shaderName);
}
simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::LoadEffectsShaders,
"Couldn't locate shader:" + shaderName, sg_location{shaderName});
throw BuilderException(string("couldn't find shader ") +
shaderName);
@@ -953,7 +962,11 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
pass->setAttributeAndModes(program);
return;
}
program = new Program;
auto sgprogram = new SGProgram;
program = sgprogram;
sgprogram->setEffectFilePath(effect->filePath());
for (const auto& skey : resolvedKey.shaders) {
const string& fileName = skey.first;
Shader::Type stype = (Shader::Type)skey.second;
@@ -964,11 +977,30 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
ref_ptr<Shader> shader = new Shader(stype);
shader->setName(fileName);
if (loadShaderFromUTF8File(shader, fileName)) {
program->addShader(shader.get());
if (!program->addShader(shader.get())) {
simgear::reportFailure(simgear::LoadFailure::BadData,
simgear::ErrorCode::LoadEffectsShaders,
"Program::addShader failed",
SGPath::fromUtf8(fileName));
}
shaderMap.insert(ShaderMap::value_type(skey, shader));
} else {
simgear::reportFailure(simgear::LoadFailure::BadData,
simgear::ErrorCode::LoadEffectsShaders,
"Failed to read shader source code",
SGPath::fromUtf8(fileName));
}
}
}
if (sgprogram->getNumShaders() == 0) {
simgear::reportFailure(simgear::LoadFailure::BadData,
simgear::ErrorCode::LoadEffectsShaders,
"No shader source code defined for effect",
effect->filePath());
}
for (const auto& key : prgKey.attributes) {
program->addBindAttribLocation(key.first, key.second);
}
@@ -1329,6 +1361,8 @@ InstallAttributeBuilder<DepthBuilder> installDepth("depth");
void buildTechnique(Effect* effect, const SGPropertyNode* prop,
const SGReaderWriterOptions* options)
{
simgear::ErrorReportContext ec("effect-technique", prop->getPath());
Technique* tniq = new Technique;
effect->techniques.push_back(tniq);
tniq->setScheme(prop->getStringValue("scheme"));
@@ -1486,16 +1520,19 @@ void mergeSchemesFallbacks(Effect *effect, const SGReaderWriterOptions *options)
// passes.
bool Effect::realizeTechniques(const SGReaderWriterOptions* options)
{
simgear::ErrorReportContext ec{"effect", getName()};
if (getPropertyRoot()->getBoolValue("/sim/version/compositor-support", false))
mergeSchemesFallbacks(this, options);
if (_isRealized)
return true;
PropertyList tniqList = root->getChildren("technique");
for (PropertyList::iterator itr = tniqList.begin(), e = tniqList.end();
itr != e;
++itr)
buildTechnique(this, *itr, options);
for (const auto& tniq : tniqList) {
buildTechnique(this, tniq, options);
}
_isRealized = true;
return true;
}
@@ -1631,3 +1668,15 @@ expression::ExpParserRegistrar propvalueRegistrar("float-property",
propertyExpressionParser<float>);
}
using namespace simgear;
void Effect::setFilePath(const SGPath& path)
{
_effectFilePath = path;
}
SGPath Effect::filePath() const
{
return _effectFilePath;
}

View File

@@ -29,10 +29,11 @@
#include <osg/observer_ptr>
#include <osgDB/ReaderWriter>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <simgear/scene/util/UpdateOnceCallback.hxx>
#include <simgear/threads/SGThread.hxx>
#include <simgear/structure/Singleton.hxx>
#include <simgear/threads/SGThread.hxx>
namespace osg
{
@@ -106,6 +107,10 @@ public:
std::string getName(){return _name;}
void setName(std::string name){_name = name;}
void setFilePath(const SGPath& path);
SGPath filePath() const;
protected:
~Effect();
// Support for a cache of effects that inherit from this one, so
@@ -142,10 +147,13 @@ protected:
Cache* _cache;
friend size_t hash_value(const Key& key);
friend Effect* makeEffect(SGPropertyNode* prop, bool realizeTechniques,
const SGReaderWriterOptions* options);
const SGReaderWriterOptions* options,
const SGPath& path);
bool _isRealized;
std::string _name;
SGPath _effectFilePath;
};
// Automatic support for boost hash function
size_t hash_value(const Effect::Key&);
@@ -156,7 +164,8 @@ Effect* makeEffect(const std::string& name,
Effect* makeEffect(SGPropertyNode* prop,
bool realizeTechniques,
const SGReaderWriterOptions* options);
const SGReaderWriterOptions* options,
const SGPath& path = SGPath{});
bool makeParametersFromStateSet(SGPropertyNode* paramRoot,
const osg::StateSet* ss);

View File

@@ -75,13 +75,13 @@ BuilderException::BuilderException()
}
BuilderException::BuilderException(const char* message, const char* origin)
: sg_exception(message, origin)
: sg_exception(message, origin, {}, false)
{
}
BuilderException::BuilderException(const std::string& message,
const std::string& origin)
: sg_exception(message, origin)
: sg_exception(message, origin, {}, false)
{
}

View File

@@ -39,12 +39,13 @@
#include <OpenThreads/Mutex>
#include <OpenThreads/ScopedLock>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/props/vectorPropTemplates.hxx>
#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/scene/util/SGSceneFeatures.hxx>
#include <simgear/scene/util/StateAttributeFactory.hxx>
#include <simgear/structure/OSGUtils.hxx>
#include <simgear/props/vectorPropTemplates.hxx>
namespace simgear
{
@@ -280,9 +281,10 @@ bool setAttrs(const TexTuple& attrs, Texture* tex,
#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
} catch (std::exception& e) {
simgear::reportFailure(simgear::LoadFailure::OutOfMemory, simgear::ErrorCode::LoadingTexture,
string{"osgDB::readRefImageFile failed:"} + e.what(),
SGPath::fromUtf8(imageName));
return false;
}
@@ -304,6 +306,9 @@ bool setAttrs(const TexTuple& attrs, Texture* tex,
tex->setMaxAnisotropy(SGSceneFeatures::instance()->getTextureFilter());
} else {
SG_LOG(SG_INPUT, SG_ALERT, "failed to load effect texture file " << imageName);
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::LoadingTexture,
"osgDB::readRefImageFile failed:" + result.message(),
SGPath::fromUtf8(imageName));
return false;
}
@@ -588,8 +593,8 @@ Texture* CubeMapBuilder::build(Effect* effect, Pass* pass, const SGPropertyNode*
const SGPropertyNode* texturesProp = getEffectPropertyChild(effect, props, "images");
const SGPropertyNode* crossProp = getEffectPropertyChild(effect, props, "image");
if (!texturesProp && !crossProp) {
simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::LoadingTexture, "No images defined for cube map");
throw BuilderException("no images defined for cube map");
return NULL; // This is redundant
}
// Using 6 separate images
@@ -770,6 +775,9 @@ Texture* CubeMapBuilder::build(Effect* effect, Pass* pass, const SGPropertyNode*
return cubeTexture.release();
} else {
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::LoadingTexture,
"Could not load cube-map image:" + result.message(),
sg_location{texname});
throw BuilderException("Could not load cube cross");
}
}
@@ -850,6 +858,9 @@ Texture* Texture3DBuilder::build(Effect* effect, Pass* pass,
tex->setImage(image3d.get());
} else {
SG_LOG(SG_INPUT, SG_ALERT, "failed to load effect texture file " << imageName);
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::LoadingTexture,
"osgDB::readRefImageFile failed:" + result.message(),
SGPath::fromUtf8(imageName));
return NULL;
}

View File

@@ -25,9 +25,11 @@
#include <osgDB/ReadFile>
#include <osgDB/Registry>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/scene/util/SGSceneFeatures.hxx>
#include <simgear/scene/util/SplicingVisitor.hxx>
#include <simgear/structure/SGExpression.hxx>
@@ -126,20 +128,20 @@ Effect* makeEffect(const string& name,
string absFileName
= SGModelLib::findDataFile(effectFileName, options);
if (absFileName.empty()) {
SG_LOG(SG_INPUT, SG_ALERT, "can't find \"" << effectFileName << "\"");
return 0;
simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::LoadEffectsShaders, "Couldn't find Effect:" + effectFileName);
return nullptr;
}
SGPropertyNode_ptr effectProps = new SGPropertyNode();
try {
readProperties(absFileName, effectProps.ptr(), 0, true);
}
catch (sg_io_exception& e) {
SG_LOG(SG_INPUT, SG_ALERT, "error reading \"" << absFileName << "\": "
<< e.getFormattedMessage());
return 0;
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::LoadEffectsShaders, e.getFormattedMessage(),
e.getLocation());
return nullptr;
}
ref_ptr<Effect> result = makeEffect(effectProps.ptr(), realizeTechniques,
options);
options, SGPath::fromUtf8(absFileName));
if (result.valid()) {
OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(effectMutex);
pair<EffectMap::iterator, bool> irslt
@@ -156,7 +158,8 @@ Effect* makeEffect(const string& name,
Effect* makeEffect(SGPropertyNode* prop,
bool realizeTechniques,
const SGReaderWriterOptions* options)
const SGReaderWriterOptions* options,
const SGPath& filePath)
{
// Give default names to techniques and passes
vector<SGPropertyNode_ptr> techniques = prop->getChildren("technique");
@@ -217,6 +220,7 @@ Effect* makeEffect(SGPropertyNode* prop,
if (!effect.valid()) {
effect = new Effect;
effect->setName(nameProp->getStringValue());
effect->setFilePath(filePath.isNull() ? parent->filePath() : filePath);
effect->root = new SGPropertyNode;
mergePropertyTrees(effect->root, prop, parent->root);
effect->parametersProp = effect->root->getChild("parameters");
@@ -234,12 +238,13 @@ Effect* makeEffect(SGPropertyNode* prop,
effect->generator = parent->generator; // Copy the generators
}
} else {
SG_LOG(SG_INPUT, SG_ALERT, "can't find base effect " <<
inheritProp->getStringValue());
return 0;
simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::LoadEffectsShaders,
string{"couldn't find base effect to inherit from:"} + inheritProp->getStringValue(), filePath);
return nullptr;
}
} else {
effect = new Effect;
effect->setFilePath(filePath);
effect->setName(nameProp->getStringValue());
effect->root = prop;
effect->parametersProp = effect->root->getChild("parameters");
@@ -266,9 +271,9 @@ Effect* makeEffect(SGPropertyNode* prop,
effect->realizeTechniques(options);
}
catch (BuilderException& e) {
SG_LOG(SG_INPUT, SG_ALERT, "Error building technique: "
<< e.getFormattedMessage());
return 0;
simgear::reportFailure(simgear::LoadFailure::Misconfigured, simgear::ErrorCode::LoadEffectsShaders,
"Failed to build technique:" + e.getFormattedMessage(), filePath);
return nullptr;
}
}
return effect.release();

View File

@@ -97,11 +97,13 @@ SGMaterial::SGMaterial( const SGReaderWriterOptions* options,
const SGPropertyNode *props,
SGPropertyNode *prop_root,
AreaList *a,
SGSharedPtr<const SGCondition> c)
SGSharedPtr<const SGCondition> c,
const std::string& n)
{
init();
areas = a;
condition = c;
region = n;
read_properties( options, props, prop_root );
buildEffectProperties(options);
}
@@ -110,12 +112,14 @@ SGMaterial::SGMaterial( const osgDB::Options* options,
const SGPropertyNode *props,
SGPropertyNode *prop_root,
AreaList *a,
SGSharedPtr<const SGCondition> c)
SGSharedPtr<const SGCondition> c,
const std::string& n)
{
osg::ref_ptr<SGReaderWriterOptions> opt;
opt = SGReaderWriterOptions::copyOrCreate(options);
areas = a;
condition = c;
region = n;
init();
read_properties(opt.get(), props, prop_root);
buildEffectProperties(opt.get());

View File

@@ -97,14 +97,16 @@ public:
const SGPropertyNode *props,
SGPropertyNode *prop_root,
AreaList *a,
SGSharedPtr<const SGCondition> c);
SGSharedPtr<const SGCondition> c,
const std::string& n);
SGMaterial(const simgear::SGReaderWriterOptions*,
const SGPropertyNode *props,
SGPropertyNode *prop_root,
AreaList *a,
SGSharedPtr<const SGCondition> c);
SGSharedPtr<const SGCondition> c,
const std::string& n);
/**
* Destructor.
@@ -123,6 +125,11 @@ public:
simgear::Effect* get_one_effect(int texIndex);
simgear::Effect* get_effect();
/**
* Get the region Name.
*/
const std::string get_region_name() const { return region; }
/**
* Get the Effect Name.
*/
@@ -487,6 +494,9 @@ private:
SGVec4f ambient, diffuse, specular, emission;
double shininess;
// region of this material
std::string region;
// effect for this material
std::string effect;

View File

@@ -83,6 +83,8 @@ bool SGMaterialLib::load( const SGPath &fg_root, const SGPath& mpath,
options->setObjectCacheHint(osgDB::Options::CACHE_ALL);
options->setDatabasePath(fg_root.utf8Str());
std::lock_guard<std::mutex> g(d->mutex);
simgear::PropertyList blocks = materialblocks.getChildren("region");
simgear::PropertyList::const_iterator block_iter = blocks.begin();
@@ -128,12 +130,13 @@ bool SGMaterialLib::load( const SGPath &fg_root, const SGPath& mpath,
// Now build all the materials for this set of areas and conditions
const std::string region = node->getStringValue("name");
const simgear::PropertyList materials = node->getChildren("material");
simgear::PropertyList::const_iterator materials_iter = materials.begin();
for (; materials_iter != materials.end(); materials_iter++) {
const SGPropertyNode *node = materials_iter->get();
SGSharedPtr<SGMaterial> m =
new SGMaterial(options.get(), node, prop_root, arealist, condition);
new SGMaterial(options.get(), node, prop_root, arealist, condition, region);
std::vector<SGPropertyNode_ptr>names = node->getChildren("name");
for ( unsigned int j = 0; j < names.size(); j++ ) {
@@ -152,14 +155,20 @@ bool SGMaterialLib::load( const SGPath &fg_root, const SGPath& mpath,
// find a material record by material name and tile center
SGMaterial *SGMaterialLib::find( const string& material, const SGVec2f center ) const
{
std::lock_guard<std::mutex> g(d->mutex);
return internalFind(material, center);
}
SGMaterial* SGMaterialLib::internalFind(const string& material, const SGVec2f center) const
{
SGMaterial *result = NULL;
const_material_map_iterator it = matlib.find( material );
if ( it != end() ) {
if (it != end()) {
// We now have a list of materials that match this
// name. Find the first one that matches.
// We start at the end of the list, as the materials
// list is ordered with the smallest regions at the end.
// We start at the end of the list, as the materials
// list is ordered with the smallest regions at the end.
material_list::const_reverse_iterator iter = it->second.rbegin();
while (iter != it->second.rend()) {
result = *iter;
@@ -183,11 +192,12 @@ SGMaterial *SGMaterialLib::find( const string& material, const SGGeod& center )
SGMaterialCache *SGMaterialLib::generateMatCache(SGVec2f center)
{
SGMaterialCache* newCache = new SGMaterialCache();
std::lock_guard<std::mutex> g(d->mutex);
material_map::const_reverse_iterator it = matlib.rbegin();
for (; it != matlib.rend(); ++it) {
newCache->insert(it->first, find(it->first, center));
newCache->insert(it->first, internalFind(it->first, center));
}
return newCache;
}

View File

@@ -81,7 +81,10 @@ private:
typedef material_map::const_iterator const_material_map_iterator;
material_map matlib;
SGMaterial* internalFind(const std::string& material, const SGVec2f center) const;
public:
// Constructor

View File

@@ -56,12 +56,15 @@
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/scene/util/NodeAndDrawableVisitor.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/io/sg_file.hxx>
#include <simgear/misc/lru_cache.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/structure/exception.hxx>
#include "BoundingVolumeBuildVisitor.hxx"
#include "model.hxx"
@@ -289,6 +292,11 @@ ModelRegistry::readImage(const string& fileName,
const SGReaderWriterOptions* sgoptC = dynamic_cast<const SGReaderWriterOptions*>(opt);
simgear::ErrorReportContext ec;
if (sgoptC && sgoptC->getModelData()) {
ec.addFromMap(sgoptC->getModelData()->getErrorContext());
}
if (cache_active && (!sgoptC || sgoptC->getLoadOriginHint() != SGReaderWriterOptions::LoadOriginHint::ORIGIN_SPLASH_SCREEN)) {
if (fileExtension != "dds" && fileExtension != "gz") {
@@ -549,7 +557,13 @@ ModelRegistry::readImage(const string& fileName,
}
}
res = registry->readImageImplementation(absFileName, opt);
try {
res = registry->readImageImplementation(absFileName, opt);
} catch (std::bad_alloc&) {
simgear::reportFailure(simgear::LoadFailure::OutOfMemory, simgear::ErrorCode::ThreeDModelLoad,
"Out of memory loading texture", sg_location{absFileName});
return ReaderWriter::ReadResult::INSUFFICIENT_MEMORY_TO_LOAD;
}
if (!res.success()) {
SG_LOG(SG_IO, SG_DEV_WARN, "Image loading failed:" << res.message());
@@ -714,7 +728,17 @@ ReaderWriter::ReadResult
ModelRegistry::readNode(const string& fileName,
const Options* opt)
{
ReaderWriter::ReadResult res;
// propogate error context from the caller
simgear::ErrorReportContext ec;
auto sgopt = dynamic_cast<const SGReaderWriterOptions*>(opt);
if (sgopt) {
if (sgopt->getModelData()) {
ec.addFromMap(sgopt->getModelData()->getErrorContext());
}
ec.addFromMap(sgopt->getErrorContext());
}
CallbackMap::iterator iter
= nodeCallbackMap.find(getFileExtension(fileName));
ReaderWriter::ReadResult result;
@@ -723,6 +747,11 @@ ModelRegistry::readNode(const string& fileName,
else
result = _defaultCallback->readNode(fileName, opt);
if (!result.validNode()) {
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::ThreeDModelLoad,
"Failed to load 3D model:" + result.message(), sg_location{fileName});
}
return result;
}

View File

@@ -35,12 +35,13 @@
#include <osgDB/FileNameUtils>
#include <simgear/compiler.h>
#include <simgear/structure/exception.hxx>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/scene/util/SGNodeMasks.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/structure/exception.hxx>
#include "modellib.hxx"
#include "SGReaderWriterXML.hxx"
@@ -81,6 +82,7 @@ SGReaderWriterXML::readNode(const std::string& name,
const osgDB::Options* options) const
{
std::string fileName = osgDB::findDataFile(name, options);
simgear::ErrorReportContext ec{"model-xml", fileName};
osg::Node *result=0;
try {
@@ -262,8 +264,10 @@ sgLoad3DModel_internal(const SGPath& path,
SGPropertyNode *overlay)
{
if (!path.exists()) {
SG_LOG(SG_IO, SG_DEV_ALERT, "Failed to load file: \"" << path << "\"");
return std::make_tuple(0, (osg::Node *) NULL);
simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::XMLModelLoad,
"Failed to load model XML: not found", path);
SG_LOG(SG_IO, SG_DEV_ALERT, "Failed to load file: \"" << path << "\"");
return std::make_tuple(0, (osg::Node*)NULL);
}
osg::ref_ptr<SGReaderWriterOptions> options;
@@ -291,6 +295,8 @@ sgLoad3DModel_internal(const SGPath& path,
try {
readProperties(modelpath, props);
} catch (const sg_exception &t) {
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::XMLModelLoad,
"Failed to load model XML:" + t.getFormattedMessage(), t.getLocation());
SG_LOG(SG_IO, SG_DEV_ALERT, "Failed to load xml: "
<< t.getFormattedMessage());
throw;
@@ -305,18 +311,24 @@ sgLoad3DModel_internal(const SGPath& path,
if (props->hasValue("/path")) {
string modelPathStr = props->getStringValue("/path");
modelpath = SGModelLib::findDataFile(modelPathStr, NULL, modelDir);
if (modelpath.isNull())
if (modelpath.isNull()) {
simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::ThreeDModelLoad,
"Model not found:" + modelPathStr, path);
throw sg_io_exception("Model file not found: '" + modelPathStr + "'",
path);
path, {}, false);
}
if (props->hasValue("/texture-path")) {
string texturePathStr = props->getStringValue("/texture-path");
if (!texturePathStr.empty())
{
texturepath = SGModelLib::findDataFile(texturePathStr, NULL, modelDir);
if (texturepath.isNull())
if (texturepath.isNull()) {
simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::LoadingTexture,
"Texture file not found:" + texturePathStr, path);
throw sg_io_exception("Texture file not found: '" + texturePathStr + "'",
path);
}
}
}
} else {
@@ -343,9 +355,13 @@ sgLoad3DModel_internal(const SGPath& path,
#else
modelResult = osgDB::readRefNodeFile(modelpath.utf8Str(), options.get());
#endif
if (!modelResult.validNode())
if (!modelResult.validNode()) {
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::XMLModelLoad,
"Failed to load 3D model:" + modelResult.message(), modelpath);
throw sg_io_exception("Failed to load 3D model:" + modelResult.message(),
modelpath);
modelpath, {}, false);
}
model = copyModel(modelResult.getNode());
// Add an extra reference to the model stored in the database.
// That is to avoid expiring the object from the cache even if
@@ -413,6 +429,9 @@ sgLoad3DModel_internal(const SGPath& path,
if (submodelPath.isNull()) {
SG_LOG(SG_IO, SG_DEV_ALERT, "Failed to load file: \"" << subPathStr << "\"");
simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::XMLModelLoad,
"Couldn't find file for submodel:" + subPathStr,
SGPath::fromUtf8(subPathStr));
continue;
}
@@ -425,6 +444,8 @@ sgLoad3DModel_internal(const SGPath& path,
}
}
simgear::ErrorReportContext("submodel", submodelPath.utf8Str());
try {
int num_anims;
std::tie(num_anims, submodel) = sgLoad3DModel_internal(submodelPath, options.get(),
@@ -553,13 +574,22 @@ sgLoad3DModel_internal(const SGPath& path,
} // of object-names in the animation
continue;
}
/*
* Setup the model data for the node currently being animated.
*/
modelData.LoadAnimationValuesForElement(animation_nodes[i], i);
try {
/*
* Setup the model data for the node currently being animated.
*/
modelData.LoadAnimationValuesForElement(animation_nodes[i], i);
/// OSGFIXME: duh, why not only model?????
SGAnimation::animate(modelData);
/// OSGFIXME: duh, why not only model?????
SGAnimation::animate(modelData);
} catch (sg_exception& e) {
simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::XMLModelLoad,
"Couldn't load animation " + animation_nodes[i]->getNameString()
+ ":" + e.getFormattedMessage(),
modelpath);
throw;
}
}
animationcount += animation_nodes.size();

View File

@@ -16,23 +16,27 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear_config.h>
#include <cstdio>
#include "SGText.hxx"
#include <simgear/math/SGMath.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/strutils.hxx>
#include <osg/Geode>
#include <osg/MatrixTransform>
#include <osgText/Text>
#include <osgText/Font>
#include <simgear/misc/ResourceManager.hxx>
#include <simgear/math/SGMath.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/scene/material/Effect.hxx>
#include <simgear/scene/material/EffectGeode.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/debug/ErrorReportingCallback.hxx>
using std::string;
class SGText::UpdateCallback : public osg::NodeCallback {
@@ -95,9 +99,15 @@ osg::Node * SGText::appendText(const SGPropertyNode* configNode,
osg::Geode * g = new osg::Geode;
g->addDrawable( text );
SGPath path("Fonts" );
path.append( configNode->getStringValue( "font", "Helvetica" ));
text->setFont( path.utf8Str() );
const std::string requestedFont = configNode->getStringValue("font","Helvetica");
const SGPath fontPath = simgear::ResourceManager::instance()->findPath("Fonts/" + requestedFont);
if ( !fontPath.isNull() ) {
text->setFont( fontPath.utf8Str() );
} else {
simgear::reportFailure(simgear::LoadFailure::NotFound,
simgear::ErrorCode::LoadingTexture,
"SGText: couldn;t find font:" + requestedFont);
}
text->setCharacterSize(configNode->getDoubleValue("character-size", 1.0 ),
configNode->getDoubleValue("character-aspect-ratio", 1.0 ));

View File

@@ -39,9 +39,11 @@
#include <simgear/bvh/BVHGroup.hxx>
#include <simgear/bvh/BVHLineGeometry.hxx>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/math/interpolater.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
#include <simgear/scene/material/EffectGeode.hxx>
#include <simgear/scene/material/EffectCullVisitor.hxx>
#include <simgear/scene/util/DeletionManager.hxx>
@@ -773,10 +775,16 @@ bool SGAnimation::setCenterAndAxisFromObject(osg::Node *rootNode, SGVec3d& cente
object_group->setNodeMask(0);
}
else {
reportFailure(LoadFailure::Misconfigured, ErrorCode::XMLModelLoad,
"Could not find valid line segment for axis animation:" + axis_object_name,
SGPath::fromUtf8(_modelData.getPath()));
SG_LOG(SG_IO, SG_DEV_ALERT, "Could not find a valid line segment for animation: " << axis_object_name << " in file: " << _modelData.getPath());
}
}
else if (can_warn) {
reportFailure(LoadFailure::Misconfigured, ErrorCode::XMLModelLoad,
"Could not find object for axis animation:" + axis_object_name,
SGPath::fromUtf8(_modelData.getPath()));
SG_LOG(SG_IO, SG_DEV_ALERT, "Could not find at least one of the following objects for axis animation: " << axis_object_name << " in file: " << _modelData.getPath());
}
}

View File

@@ -24,11 +24,12 @@
#include <simgear/scene/util/SplicingVisitor.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/structure/Singleton.hxx>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/props/condition.hxx>
#include <simgear/structure/Singleton.hxx>
#include <simgear/structure/exception.hxx>
#include "model.hxx"
@@ -380,6 +381,8 @@ ref_ptr<Node> instantiateMaterialEffects(osg::Node* modelGroup,
} else {
effect = DefaultEffect::instance()->getEffect();
SG_LOG( SG_TERRAIN, SG_ALERT, "Unable to get effect for " << options->getMaterialName());
simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::LoadEffectsShaders,
"Unable to get effect for material:" + options->getMaterialName());
}
} else {
effect = DefaultEffect::instance()->getEffect();

View File

@@ -29,12 +29,13 @@
#include <osgDB/Registry>
#include <simgear/constants.h>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/misc/ResourceManager.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/scene/model/model.hxx>
#include <simgear/scene/model/ModelRegistry.hxx>
#include <simgear/scene/model/model.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/misc/ResourceManager.hxx>
#include "SGReaderWriterXML.hxx"
@@ -159,7 +160,6 @@ SGModelLib::loadDeferredModel(const string &path, SGPropertyNode *prop_root,
proxyNode->setLoadingExternalReferenceMode(osg::ProxyNode::DEFER_LOADING_TO_DATABASE_PAGER);
proxyNode->setFileName(0, path);
osg::ref_ptr<SGReaderWriterOptions> opt;
opt = SGReaderWriterOptions::copyOrCreate(osgDB::Registry::instance()->getOptions());
opt->getDatabasePathList().push_front( osgDB::getFilePath(path) );

View File

@@ -18,12 +18,9 @@
#ifndef _SG_MODEL_LIB_HXX
#define _SG_MODEL_LIB_HXX 1
#ifndef __cplusplus
# error This library requires C++
#endif
#include <simgear/compiler.h> // for SG_USING_STD
#include <map>
#include <string>
#include <osg/Node>
@@ -112,6 +109,10 @@ public:
virtual void modelLoaded(const std::string& path, SGPropertyNode *prop,
osg::Node* branch) = 0;
virtual SGModelData* clone() const = 0;
using ErrorContext = std::map<std::string, std::string>;
virtual ErrorContext getErrorContext() const = 0;
};
/*

View File

@@ -512,6 +512,14 @@ void Particles::setupStaticColorComponent(float r1, float g1, float b1, float a1
staticColorComponents[7] = a2;
}
ParticlesGlobalManager::~ParticlesGlobalManager()
{
// break a ref-counting cycle
if (d->_commonRoot) {
d->_commonRoot->removeUpdateCallback(d.get());
}
}
void ParticlesGlobalManager::setWindVector(const osg::Vec3& wind)
{
std::lock_guard<std::mutex> g(d->_lock);

View File

@@ -150,7 +150,7 @@ protected:
class ParticlesGlobalManager
{
public:
~ParticlesGlobalManager() = default;
~ParticlesGlobalManager();
static ParticlesGlobalManager* instance();
static void clear();

View File

@@ -38,10 +38,12 @@
#include <osgDB/ReaderWriter>
#include <osgDB/ReadFile>
#include <simgear/math/sg_random.h>
#include <simgear/math/SGGeometry.hxx>
#include <simgear/bucket/newbucket.hxx>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/math/SGGeometry.hxx>
#include <simgear/math/sg_random.h>
#include <simgear/io/iostreams/sgstream.hxx>
#include <simgear/scene/util/OptionsReadFileCallback.hxx>
#include <simgear/scene/util/OsgMath.hxx>
@@ -154,7 +156,7 @@ struct ReaderWriterSTG::_ModelBin {
proxy->setName("proxyNode");
proxy->setLoadingExternalReferenceMode(osg::ProxyNode::DEFER_LOADING_TO_DATABASE_PAGER);
proxy->setFileName(0, o._name);
proxy->setDatabaseOptions(o._options.get());
proxy->setDatabaseOptions(o._options);
// Give the node some values so the Quadtree builder has
// a BoundingBox to work with prior to the model being loaded.
@@ -163,6 +165,7 @@ struct ReaderWriterSTG::_ModelBin {
proxy->setCenterMode(osg::ProxyNode::UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED);
node = proxy;
} else {
ErrorReportContext ec("terrain-stg", o._errorLocation.utf8Str());
#if OSG_VERSION_LESS_THAN(3,4,0)
node = osgDB::readNodeFile(o._name, o._options.get());
#else
@@ -209,6 +212,8 @@ struct ReaderWriterSTG::_ModelBin {
virtual osgDB::ReaderWriter::ReadResult
readNode(const std::string&, const osgDB::Options*)
{
ErrorReportContext ec("terrain-bucket", _bucket.gen_index_str());
STGObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD()));
quadtree.buildQuadTree(_objectStaticList.begin(), _objectStaticList.end());
osg::ref_ptr<osg::Group> group = quadtree.getRoot();
@@ -465,15 +470,15 @@ struct ReaderWriterSTG::_ModelBin {
else
opt->setInstantiateEffects(false);
_ObjectStatic obj;
obj._errorLocation = absoluteFileName;
obj._token = token;
obj._name = name;
obj._agl = (token == "OBJECT_STATIC_AGL");
obj._proxy = true;
in >> obj._lon >> obj._lat >> obj._elev >> obj._hdg >> obj._pitch >> obj._roll;
obj._range = range;
obj._options = opt;
opt->addErrorContext("terrain-stg", absoluteFileName.utf8Str());
obj._errorLocation = absoluteFileName;
obj._token = token;
obj._name = name;
obj._agl = (token == "OBJECT_STATIC_AGL");
obj._proxy = true;
in >> obj._lon >> obj._lat >> obj._elev >> obj._hdg >> obj._pitch >> obj._roll;
obj._range = range;
obj._options = opt;
checkInsideBucket(absoluteFileName, obj._lon, obj._lat);
_objectStaticList.push_back(obj);
} else if (token == "OBJECT_SHARED" || token == "OBJECT_SHARED_AGL") {
@@ -509,6 +514,8 @@ struct ReaderWriterSTG::_ModelBin {
_ObjectStatic obj;
opt->setInstantiateEffects(false);
opt->addErrorContext("terrain-stg", absoluteFileName.utf8Str());
if (SGPath(name).lower_extension() == "ac") {
// Generate material/Effects lookups for raw models, i.e.
// those not wrapped in an XML while will include Effects
@@ -573,7 +580,9 @@ struct ReaderWriterSTG::_ModelBin {
}
callback(token,name, SGGeod::fromDegM(obj._lon, obj._lat, obj._elev), obj._hdg,restofline);
} else {
SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName << ": Unknown token '" << token << "'" );
// SG_LOG( SG_TERRAIN, SG_ALERT, absoluteFileName << ": Unknown token '" << token << "'" );
simgear::reportFailure(simgear::LoadFailure::Misconfigured, simgear::ErrorCode::BTGLoad,
"Unknown STG token:" + token, absoluteFileName);
}
}
}
@@ -594,9 +603,13 @@ struct ReaderWriterSTG::_ModelBin {
std::string terrain_name = string("terrain ").append(bucket.gen_index_str());
terrainGroup->setName(terrain_name);
simgear::ErrorReportContext ec{"terrain-bucket", bucket.gen_index_str()};
if (_foundBase) {
for (auto stgObject : _objectList) {
osg::ref_ptr<osg::Node> node;
simgear::ErrorReportContext ec("terrain-stg", stgObject._errorLocation.utf8Str());
#if OSG_VERSION_LESS_THAN(3,4,0)
node = osgDB::readNodeFile(stgObject._name, stgObject._options.get());
#else
@@ -621,7 +634,6 @@ struct ReaderWriterSTG::_ModelBin {
"Warning: failed to generate ocean tile!" );
}
}
for (std::list<_ObjectStatic>::iterator i = _objectStaticList.begin(); i != _objectStaticList.end(); ++i) {
if (!i->_agl)
continue;
@@ -701,6 +713,7 @@ ReaderWriterSTG::readNode(const std::string& fileName, const osgDB::Options* opt
{
_ModelBin modelBin;
SGBucket bucket(bucketIndexFromFileName(fileName));
simgear::ErrorReportContext ec("terrain-bucket", bucket.gen_index_str());
// We treat 123.stg different than ./123.stg.
// The difference is that ./123.stg as well as any absolute path
@@ -708,6 +721,7 @@ ReaderWriterSTG::readNode(const std::string& fileName, const osgDB::Options* opt
// In contrast 123.stg uses the search paths to load a set of stg
// files spread across the scenery directories.
if (osgDB::getSimpleFileName(fileName) != fileName) {
simgear::ErrorReportContext ec("terrain-stg", fileName);
if (!modelBin.read(fileName, options))
return ReadResult::FILE_NOT_FOUND;
}
@@ -717,11 +731,10 @@ ReaderWriterSTG::readNode(const std::string& fileName, const osgDB::Options* opt
return ReadResult::FILE_NOT_FOUND;
}
osg::ref_ptr<SGReaderWriterOptions> sgOpts(SGReaderWriterOptions::copyOrCreate(options));
if (sgOpts->getSceneryPathSuffixes().empty()) {
const auto sgOpts = dynamic_cast<const SGReaderWriterOptions*>(options);
if (!sgOpts || sgOpts->getSceneryPathSuffixes().empty()) {
SG_LOG(SG_TERRAIN, SG_ALERT, "Loading tile " << fileName << ", no scenery path suffixes were configured so giving up");
return ReadResult::FILE_NOT_FOUND;
}
SG_LOG(SG_TERRAIN, SG_INFO, "Loading tile " << fileName);
@@ -746,7 +759,8 @@ ReaderWriterSTG::readNode(const std::string& fileName, const osgDB::Options* opt
}
for (auto suffix : sgOpts->getSceneryPathSuffixes()) {
SGPath p = base / suffix / basePath / fileName;
const auto p = base / suffix / basePath / fileName;
simgear::ErrorReportContext ec("terrain-stg", p.utf8Str());
modelBin.read(p, options);
}
}

View File

@@ -22,6 +22,7 @@
#include <osgDB/FileNameUtils>
#include <osgDB/Registry>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/scene/model/ModelRegistry.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/structure/exception.hxx>
@@ -62,16 +63,22 @@ SGReaderWriterBTG::readNode(const std::string& fileName,
const SGReaderWriterOptions* sgOptions;
sgOptions = dynamic_cast<const SGReaderWriterOptions*>(options);
osg::Node* result = NULL;
simgear::ErrorReportContext ec{"btg", fileName};
try {
result = SGLoadBTG(fileName, sgOptions);
if (!result)
return ReadResult::FILE_NOT_HANDLED;
} catch (sg_exception& e) {
SG_LOG(SG_IO, SG_WARN, "error reading:" << fileName << ":" <<
e.getFormattedMessage());
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::BTGLoad,
"Failed to load BTG file:" + e.getFormattedMessage(),
e.getLocation());
return ReadResult::ERROR_IN_READING_FILE;
} catch (std::bad_alloc&) {
simgear::reportFailure(simgear::LoadFailure::OutOfMemory, simgear::ErrorCode::BTGLoad,
"Out of memory loading BTG:" + fileName, sg_location{fileName});
return ReadResult::ERROR_IN_READING_FILE;
}
return result;
}

View File

@@ -37,6 +37,7 @@
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/scene/util/OptionsReadFileCallback.hxx>
#include <simgear/scene/util/SGNodeMasks.hxx>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include "SGNodeTriangles.hxx"
#include "GroundLightManager.hxx"
@@ -55,9 +56,11 @@ typedef std::list<SGDirectionalLightBin> SGDirectionalLightListBin;
#define SG_SIMPLIFIER_RATIO (0.001)
#define SG_SIMPLIFIER_MAX_LENGTH (1000.0)
#define SG_SIMPLIFIER_MAX_ERROR (2000.0)
#define SG_TILE_MIN_EXPIRY (180.0)
using namespace simgear;
using ReadResult = osgDB::ReaderWriter::ReadResult;
// QuadTreeBuilder is used by Random Objects Generator
typedef std::pair<osg::Node*, int> ModelLOD;
struct MakeQuadLeaf {
@@ -97,47 +100,59 @@ public:
SG_LOG( SG_TERRAIN, SG_DEBUG, "SGTileDetailsCallback::~SGTileDetailsCallback() num cbs left " << num_tdcb );
}
virtual osgDB::ReaderWriter::ReadResult readNode(
const std::string&, const osgDB::Options*)
ReadResult readNode(const std::string&, const osgDB::Options*) override
{
SGMaterialLibPtr matlib;
osg::ref_ptr<SGMaterialCache> matcache;
osg::ref_ptr<osg::Group> group = new osg::Group;
group->setDataVariance(osg::Object::STATIC);
osg::ref_ptr<osg::Group> group;
simgear::ErrorReportContext ec{"btg", _path};
// generate textured triangle list
std::vector<SGTriangleInfo> matTris;
GetNodeTriangles nodeTris(_gbs_center, &matTris);
_rootNode->accept( nodeTris );
try {
group = new osg::Group;
SGMaterialLibPtr matlib;
osg::ref_ptr<SGMaterialCache> matcache;
group->setDataVariance(osg::Object::STATIC);
// build matcache
matlib = _options->getMaterialLib();
if (matlib) {
SGGeod geodPos = SGGeod::fromCart(_gbs_center);
matcache = matlib->generateMatCache(geodPos);
}
#if 0
// TEST : See if we can regenerate landclass shapes from node
for ( unsigned int i=0; i<matTris.size(); i++ ) {
matTris[i].dumpBorder(_gbs_center);
}
#endif
// generate textured triangle list
std::vector<SGTriangleInfo> matTris;
GetNodeTriangles nodeTris(_gbs_center, &matTris);
_rootNode->accept( nodeTris );
osg::Node* node = loadTerrain();
if (node) {
group->addChild(node);
}
// build matcache
matlib = _options->getMaterialLib();
if (matlib) {
SGGeod geodPos = SGGeod::fromCart(_gbs_center);
matcache = matlib->generateMatCache(geodPos);
}
#if 0
// TEST : See if we can regenerate landclass shapes from node
for ( unsigned int i=0; i<matTris.size(); i++ ) {
matTris[i].dumpBorder(_gbs_center);
}
#endif
osg::LOD* lightLOD = generateLightingTileObjects(matTris, matcache);
if (lightLOD) {
group->addChild(lightLOD);
}
osg::Node* node = loadTerrain();
if (node) {
group->addChild(node);
}
osg::LOD* objectLOD = generateRandomTileObjects(matTris, matcache);
if (objectLOD) {
group->addChild(objectLOD);
osg::LOD* lightLOD = generateLightingTileObjects(matTris, matcache);
if (lightLOD) {
group->addChild(lightLOD);
}
osg::LOD* objectLOD = generateRandomTileObjects(matTris, matcache);
if (objectLOD) {
group->addChild(objectLOD);
}
} catch (sg_exception& sge) {
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::BTGLoad,
"Failed to load BTG file:" + sge.getFormattedMessage(),
sge.getLocation());
return ReadResult::ERROR_IN_READING_FILE;
} catch (std::bad_alloc &e) {
simgear::reportFailure(simgear::LoadFailure::OutOfMemory, simgear::ErrorCode::BTGLoad,
"Out of memory loading tile details", sg_location{_path});
return ReadResult::INSUFFICIENT_MEMORY_TO_LOAD;
}
return group.release();

View File

@@ -1124,6 +1124,9 @@ void SGTerraSync::reinit()
SGPath sceneryRoot{_terraRoot->getStringValue("scenery-dir", "")};
_workerThread->setLocalDir(sceneryRoot.utf8Str());
if (sceneryRoot.exists()) {
writeWarningFile(sceneryRoot);
}
SGPath installPath(_terraRoot->getStringValue("installation-dir"));
_workerThread->setInstalledDir(installPath);
@@ -1362,6 +1365,23 @@ void SGTerraSync::reposition()
// stub, remove
}
void SGTerraSync::writeWarningFile(const SGPath& sceneryDir)
{
SGPath p = sceneryDir / "TerraSync-WARNING.txt";
if (p.exists())
return;
sg_ofstream os(p, std::ios::out | std::ios::trunc);
os << "This folder is managed by FlightGear's download system.\n";
os << "Any changes you make here or in sub-folders will be overwritten when TerraSync\n";
os << "downloads updates.\n";
os << "\n";
os << "To use custom scenery or data with FlightGear, put it in a differnet location\n";
os << "on your computer, then add the location using either the launcher 'Add-ons' page, or by\n";
os << "passing '--fg-scenery=<location>' on the command line.";
os << endl;
}
// Register the subsystem.
SGSubsystemMgr::Registrant<SGTerraSync> registrantSGTerraSync(

View File

@@ -90,6 +90,9 @@ protected:
class WorkerThread;
private:
void writeWarningFile(const SGPath& sceneryDir);
private:
WorkerThread* _workerThread;
SGPropertyNode_ptr _terraRoot;

View File

@@ -31,6 +31,7 @@ set(HEADERS
UpdateOnceCallback.hxx
VectorArrayAdapter.hxx
project.hxx
SGProgram.hxx
)
set(SOURCES
@@ -55,6 +56,7 @@ set(SOURCES
StateAttributeFactory.cxx
UpdateOnceCallback.cxx
project.cxx
SGProgram.cxx
)
simgear_scene_component(util scene/util "${SOURCES}" "${HEADERS}")

View File

@@ -0,0 +1,83 @@
////
// 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 Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
// Boston, MA 02110-1301, USA.
#include "simgear_config.h"
#include "SGProgram.hxx"
#include <osg/State>
#include <sstream>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include <simgear/debug/logstream.hxx>
SGProgram::SGProgram()
{
}
SGProgram::SGProgram(const SGProgram& rhs, const osg::CopyOp& copyop) : osg::Program(rhs, copyop),
_effectFilePath(rhs._effectFilePath)
{
}
void SGProgram::setEffectFilePath(const SGPath& p)
{
_effectFilePath = p;
}
void SGProgram::apply(osg::State& state) const
{
osg::Program::apply(state);
if (_checkState != NotApplied) {
return; // already done
}
auto pcp = state.getLastAppliedProgramObject();
if (!pcp) {
std::string infoLog;
_checkState = FailedToApply;
getPCP(state)->getInfoLog(infoLog);
if (!infoLog.empty()) {
// log all the shader source file names, to help in debugging link errors
std::ostringstream os;
for (int i = 0; i < getNumShaders(); ++i) {
const auto shader = getShader(i);
os << "\t" << shader->getFileName() << "\n";
}
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::LoadEffectsShaders,
"Shader program errors: " + infoLog +
"\n\nShader sources:\n" + os.str(),
_effectFilePath);
}
for (int i = 0; i < getNumShaders(); ++i) {
const auto shader = getShader(i);
auto pcs = shader->getPCS(state);
std::string shaderLog;
pcs->getInfoLog(shaderLog);
if (!shaderLog.empty()) {
simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::LoadEffectsShaders,
"Shader source errors: " + shaderLog, sg_location(shader->getFileName()));
}
}
} else {
_checkState = AppliedOk;
}
}

View File

@@ -0,0 +1,50 @@
////
// 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 Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
// Boston, MA 02110-1301, USA.
#pragma once
#include <osg/Program>
#include <simgear/misc/sg_path.hxx>
/**
* @brief wrapper around osg::Program to allow detecting shader/link
* errors in the GLSL code at runtime, and reporting of them
*
*/
class SGProgram : public osg::Program
{
public:
SGProgram();
SGProgram(const SGProgram& rhs, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
META_StateAttribute(simgear, SGProgram, PROGRAM);
void apply(osg::State& state) const override;
enum ErrorCheckState {
NotApplied,
AppliedOk,
FailedToApply
};
void setEffectFilePath(const SGPath& p);
private:
SGPath _effectFilePath;
mutable ErrorCheckState _checkState = NotApplied;
};

View File

@@ -17,9 +17,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear_config.h>
#include <simgear/scene/util/OsgMath.hxx>
@@ -54,4 +52,10 @@ SGReaderWriterOptions::fromPath(const SGPath& path)
return options;
}
void SGReaderWriterOptions::addErrorContext(const std::string& key, const std::string& value)
{
_errorContext[key] = value;
}
} // namespace simgear

View File

@@ -76,12 +76,11 @@ public:
_LoadOriginHint(ORIGIN_MODEL)
{ }
SGReaderWriterOptions(const SGReaderWriterOptions& options,
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) :
osgDB::Options(options, copyop),
_propertyNode(options._propertyNode),
_materialLib(options._materialLib),
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) : osgDB::Options(options, copyop),
_propertyNode(options._propertyNode),
_materialLib(options._materialLib),
#ifdef ENABLE_GDAL
_dem(options._dem),
_dem(options._dem),
#endif
_load_panel(options._load_panel),
_model_data(options._model_data),
@@ -89,7 +88,8 @@ public:
_instantiateMaterialEffects(options._instantiateMaterialEffects),
_materialName(options._materialName),
_sceneryPathSuffixes(options._sceneryPathSuffixes),
_LoadOriginHint(ORIGIN_MODEL)
_LoadOriginHint(ORIGIN_MODEL),
_errorContext(options._errorContext)
{ }
META_Object(simgear, SGReaderWriterOptions);
@@ -158,7 +158,16 @@ public:
// any texture that is used in a shader, as these often have special values
// encoded into the channels that aren't suitable for conversion.
void setLoadOriginHint(LoadOriginHint _v) const { _LoadOriginHint = _v; }
LoadOriginHint getLoadOriginHint() const { return _LoadOriginHint; }
LoadOriginHint getLoadOriginHint() const { return _LoadOriginHint; }
using ErrorContext = std::map<std::string, std::string>;
void addErrorContext(const std::string& key, const std::string& value);
ErrorContext getErrorContext() const
{
return _errorContext;
}
protected:
virtual ~SGReaderWriterOptions();
@@ -179,6 +188,7 @@ private:
string_list _sceneryPathSuffixes;
SGGeod _geod;
mutable LoadOriginHint _LoadOriginHint;
ErrorContext _errorContext;
};
}

View File

@@ -32,6 +32,7 @@
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/stdint.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/debug/ErrorReportingCallback.hxx>
#include "sample.hxx"
@@ -56,7 +57,7 @@ namespace
}
};
unsigned int formatConstruct(ALint numChannels, ALint bitsPerSample, bool compressed)
unsigned int formatConstruct(ALint numChannels, ALint bitsPerSample, bool compressed, const SGPath& path)
{
unsigned int rv = 0;
if (!compressed) {
@@ -67,7 +68,7 @@ namespace
else {
char msg[81];
snprintf(msg, 80, "Unsupported audio format: tracks: %i, bits/sample: %i", numChannels, bitsPerSample);
throw sg_exception(msg);
throw sg_exception(msg, {}, path, false);
}
} else {
if (numChannels == 1 && bitsPerSample == 4) rv = SG_SAMPLE_ADPCM;
@@ -75,7 +76,7 @@ namespace
else {
char msg[81];
snprintf(msg, 80, "Unsupported compressed audio format: tracks: %i, bits/sample: %i", numChannels, bitsPerSample);
throw sg_exception(msg);
throw sg_exception(msg, {}, path, false);
}
}
return rv;
@@ -275,29 +276,29 @@ namespace
Codec *codec = codecLinear;
if (!wavReadBE(fd, magic))
throw sg_io_exception("corrupt or truncated WAV data", b->path);
throw sg_io_exception("corrupt or truncated WAV data", b->path, {}, false);
if (magic != WAV_RIFF_4CC) {
throw sg_io_exception("not a .wav file", b->path);
throw sg_io_exception("not a .wav file", b->path, {}, false);
}
if (!wavReadLE(fd, chunkLength) || !wavReadBE(fd, magic))
throw sg_io_exception("corrupt or truncated WAV data", b->path);
throw sg_io_exception("corrupt or truncated WAV data", b->path, {}, false);
if (magic != WAV_WAVE_4CC) /* "WAVE" */
{
throw sg_io_exception("unrecognized WAV magic", b->path);
throw sg_io_exception("unrecognized WAV magic", b->path, {}, false);
}
while (1) {
if (!wavReadBE(fd, magic) || !wavReadLE(fd, chunkLength))
throw sg_io_exception("corrupt or truncated WAV data", b->path);
throw sg_io_exception("corrupt or truncated WAV data", b->path, {}, false);
if (magic == WAV_FORMAT_4CC) /* "fmt " */
{
found_header = true;
if (chunkLength < 16) {
throw sg_io_exception("corrupt or truncated WAV data", b->path);
throw sg_io_exception("corrupt or truncated WAV data", b->path, {}, false);
}
if (!wavReadLE (fd, audioFormat) ||
@@ -307,11 +308,11 @@ namespace
!wavReadLE (fd, blockAlign) ||
!wavReadLE (fd, bitsPerSample))
{
throw sg_io_exception("corrupt or truncated WAV data", b->path);
throw sg_io_exception("corrupt or truncated WAV data", b->path, {}, false);
}
if (!gzSkip(fd, chunkLength - 16))
throw sg_io_exception("corrupt or truncated WAV data", b->path);
throw sg_io_exception("corrupt or truncated WAV data", b->path, {}, false);
switch (audioFormat)
{
@@ -340,33 +341,33 @@ namespace
}
break;
default:
throw sg_io_exception("unsupported WAV encoding", b->path);
throw sg_io_exception("unsupported WAV encoding:" + std::to_string(audioFormat), b->path, {}, false);
}
b->block_align = blockAlign;
b->frequency = samplesPerSecond;
b->format = formatConstruct(numChannels, bitsPerSample, compressed);
b->format = formatConstruct(numChannels, bitsPerSample, compressed, b->path);
} else if (magic == WAV_DATA_4CC) {
if (!found_header) {
/* ToDo: A bit wrong to check here, fmt chunk could come later... */
throw sg_io_exception("corrupt or truncated WAV data", b->path);
throw sg_io_exception("corrupt or truncated WAV data", b->path, {}, false);
}
b->data = malloc(chunkLength);
b->length = chunkLength;
size_t read = gzread(fd, b->data, chunkLength);
if (read != chunkLength) {
throw sg_io_exception("insufficent data reading WAV file", b->path);
throw sg_io_exception("insufficent data reading WAV file", b->path, {}, false);
}
break;
} else {
if (!gzSkip(fd, chunkLength))
throw sg_io_exception("corrupt or truncated WAV data", b->path);
throw sg_io_exception("corrupt or truncated WAV data", b->path, {}, false);
}
if ((chunkLength & 1) && !gzeof(fd) && !gzSkip(fd, 1))
throw sg_io_exception("corrupt or truncated WAV data", b->path);
throw sg_io_exception("corrupt or truncated WAV data", b->path, {}, false);
} // of file chunk parser loop
codec(b); // might throw if something really bad occurs
@@ -380,7 +381,7 @@ namespace simgear
ALvoid* loadWAVFromFile(const SGPath& path, unsigned int& format, ALsizei& size, ALfloat& freqf, unsigned int& block_align)
{
if (!path.exists()) {
SG_LOG(SG_IO, SG_DEV_ALERT, "loadWAVFromFile: file not found:" << path);
simgear::reportFailure(simgear::LoadFailure::NotFound, simgear::ErrorCode::AudioFX, "loadWAVFromFile: not found", path);
return nullptr;
}
@@ -396,14 +397,15 @@ ALvoid* loadWAVFromFile(const SGPath& path, unsigned int& format, ALsizei& size,
fd = gzopen(ps.c_str(), "rb");
#endif
if (!fd) {
SG_LOG(SG_IO, SG_DEV_ALERT, "loadWAVFromFile: unable to open file:" << path);
simgear::reportFailure(simgear::LoadFailure::IOError, simgear::ErrorCode::AudioFX, "loadWAVFromFile: unable to open file", path);
return nullptr;
}
try {
loadWavFile(fd, &b);
} catch (sg_exception& e) {
SG_LOG(SG_IO, SG_DEV_ALERT, "loadWAVFromFile:" << e.getFormattedMessage() << "\nfor: " << path);
simgear::reportFailure(simgear::LoadFailure::IOError, simgear::ErrorCode::AudioFX, "loadWAVFromFile: unable to read file:"
+ e.getFormattedMessage(), e.getLocation());
return nullptr;
}

View File

@@ -343,7 +343,7 @@ public:
* Schedule this audio sample to stop (or start) playing.
*/
inline void set_out_of_range(bool oor = true) {
_out_of_range = oor; _playing = (!oor && _loop); _changed = true;
_out_of_range = oor; _changed = true;
}
/**

View File

@@ -347,7 +347,9 @@ SGXmlSound::update (double dt)
// else
// if a property is defined then test if it's value is FALSE
// or if the mode is IN_TRANSIT then
// test whether the current value matches the previous value.
// test whether the current value matches the previous value,
// else
// check if out of range.
if ( // Lisp, anyone?
(_condition && !_condition->test()) ||
(!_condition && _property &&
@@ -355,7 +357,8 @@ SGXmlSound::update (double dt)
!curr_value ||
( (_mode == SGXmlSound::IN_TRANSIT) && (curr_value == _prev_value) )
)
)
) ||
_sample->test_out_of_range()
)
{
if ((_mode != SGXmlSound::IN_TRANSIT) || (_stopping > MAX_TRANSIT_TIME))

View File

@@ -19,66 +19,65 @@ static ThrowCallback static_callback;
// Implementation of sg_location class.
////////////////////////////////////////////////////////////////////////
sg_location::sg_location ()
: _line(-1),
_column(-1),
_byte(-1)
sg_location::sg_location() noexcept
: _line(-1),
_column(-1),
_byte(-1)
{
_path[0] = '\0';
}
sg_location::sg_location (const std::string& path, int line, int column)
: _line(line),
_column(column),
_byte(-1)
sg_location::sg_location(const std::string& path, int line, int column) noexcept
: _line(line),
_column(column),
_byte(-1)
{
setPath(path.c_str());
}
sg_location::sg_location (const SGPath& path, int line, int column)
: _line(line),
_column(column),
_byte(-1)
sg_location::sg_location(const SGPath& path, int line, int column) noexcept
: _line(line),
_column(column),
_byte(-1)
{
setPath(path.utf8Str().c_str());
}
sg_location::sg_location (const char* path, int line, int column)
: _line(line),
_column(column),
_byte(-1)
sg_location::sg_location(const char* path, int line, int column) noexcept
: _line(line),
_column(column),
_byte(-1)
{
setPath(path);
}
void sg_location::setPath(const char *path) {
if (path) {
strncpy(_path, path, max_path);
_path[max_path -1] = '\0';
} else {
_path[0] = '\0';
}
void sg_location::setPath(const char* path) noexcept
{
if (path) {
strncpy(_path, path, max_path);
_path[max_path - 1] = '\0';
} else {
_path[0] = '\0';
}
}
const char *sg_location::getPath() const { return _path; }
const char* sg_location::getPath() const noexcept { return _path; }
int sg_location::getLine() const { return _line; }
int sg_location::getLine() const noexcept { return _line; }
int
sg_location::getColumn () const
int sg_location::getColumn() const noexcept
{
return _column;
}
int
sg_location::getByte () const
int sg_location::getByte() const noexcept
{
return _byte;
}
std::string
sg_location::asString () const
sg_location::asString() const noexcept
{
std::ostringstream out;
if (_path[0]) {
@@ -97,46 +96,48 @@ sg_location::asString () const
return out.str();
}
bool sg_location::isValid() const { return strlen(_path) > 0; }
bool sg_location::isValid() const noexcept { return strlen(_path) > 0; }
////////////////////////////////////////////////////////////////////////
// Implementation of sg_throwable class.
////////////////////////////////////////////////////////////////////////
sg_throwable::sg_throwable ()
sg_throwable::sg_throwable() noexcept
{
_message[0] = '\0';
_origin[0] = '\0';
}
sg_throwable::sg_throwable(const char *message, const char *origin,
const sg_location &loc) {
setMessage(message);
setOrigin(origin);
if (static_callback) {
static_callback(_message, _origin, loc);
}
}
sg_throwable::~sg_throwable ()
sg_throwable::sg_throwable(const char* message, const char* origin,
const sg_location& loc, bool report) noexcept : _location(loc)
{
setMessage(message);
setOrigin(origin);
if (static_callback && report) {
static_callback(_message, _origin, loc);
}
}
const char*
sg_throwable::getMessage () const
sg_throwable::getMessage() const noexcept
{
return _message;
}
const std::string
sg_throwable::getFormattedMessage () const
std::string
sg_throwable::getFormattedMessage() const noexcept
{
return std::string(getMessage());
std::string ret = getMessage();
const std::string loc = getLocation().asString();
if (loc.length()) {
ret += "\n at ";
ret += loc;
}
return ret;
}
void
sg_throwable::setMessage (const char* message)
void sg_throwable::setMessage(const char* message) noexcept
{
strncpy(_message, message, MAX_TEXT_LEN);
_message[MAX_TEXT_LEN - 1] = '\0';
@@ -144,13 +145,12 @@ sg_throwable::setMessage (const char* message)
}
const char*
sg_throwable::getOrigin () const
sg_throwable::getOrigin() const noexcept
{
return _origin;
}
void
sg_throwable::setOrigin (const char* origin)
void sg_throwable::setOrigin(const char* origin) noexcept
{
if (origin) {
strncpy(_origin, origin, MAX_TEXT_LEN);
@@ -170,27 +170,27 @@ const char* sg_throwable::what() const noexcept
}
}
sg_location sg_throwable::getLocation() const noexcept
{
return _location;
}
void sg_throwable::setLocation(const sg_location& location) noexcept
{
_location = location;
}
////////////////////////////////////////////////////////////////////////
// Implementation of sg_error class.
////////////////////////////////////////////////////////////////////////
sg_error::sg_error ()
: sg_throwable ()
sg_error::sg_error(const char* message, const char* origin, bool report) noexcept
: sg_throwable(message, origin, {}, report)
{
}
sg_error::sg_error (const char* message, const char *origin)
: sg_throwable(message, origin)
{
}
sg_error::sg_error(const std::string& message, const std::string& origin)
: sg_throwable(message.c_str(), origin.c_str())
{
}
sg_error::~sg_error ()
sg_error::sg_error(const std::string& message, const std::string& origin, bool report) noexcept
: sg_throwable(message.c_str(), origin.c_str(), {}, report)
{
}
@@ -198,121 +198,81 @@ sg_error::~sg_error ()
// Implementation of sg_exception class.
////////////////////////////////////////////////////////////////////////
sg_exception::sg_exception ()
: sg_throwable ()
{
}
sg_exception::sg_exception(const char* message, const char* origin,
const sg_location& loc, bool report) noexcept
: sg_throwable(message, origin, loc, report) {}
sg_exception::sg_exception(const char *message, const char *origin,
const sg_location &loc)
: sg_throwable(message, origin, loc) {}
sg_exception::sg_exception(const std::string& message,
const std::string& origin, const sg_location& loc,
bool report) noexcept
: sg_throwable(message.c_str(), origin.c_str(), loc, report) {}
sg_exception::sg_exception(const std::string &message,
const std::string &origin, const sg_location &loc)
: sg_throwable(message.c_str(), origin.c_str(), loc) {}
sg_exception::~sg_exception ()
{
}
////////////////////////////////////////////////////////////////////////
// Implementation of sg_io_exception.
////////////////////////////////////////////////////////////////////////
sg_io_exception::sg_io_exception ()
: sg_exception()
sg_io_exception::sg_io_exception(const char* message, const char* origin, bool report)
: sg_exception(message, origin, {}, report)
{
}
sg_io_exception::sg_io_exception (const char* message, const char* origin)
: sg_exception(message, origin)
sg_io_exception::sg_io_exception(const char* message,
const sg_location& location,
const char* origin,
bool report)
: sg_exception(message, origin, location, report) {}
sg_io_exception::sg_io_exception(const std::string& message,
const std::string& origin,
bool report)
: sg_exception(message, origin, {}, report)
{
}
sg_io_exception::sg_io_exception(const char *message,
const sg_location &location,
const char *origin)
: sg_exception(message, origin, location), _location(location) {}
sg_io_exception::sg_io_exception( const std::string& message,
const std::string& origin )
: sg_exception(message, origin)
{
}
sg_io_exception::sg_io_exception(const std::string &message,
const sg_location &location,
const std::string &origin)
: sg_exception(message, origin, location), _location(location) {}
sg_io_exception::~sg_io_exception ()
{
}
const std::string
sg_io_exception::getFormattedMessage () const
{
std::string ret = getMessage();
std::string loc = getLocation().asString();
if (loc.length()) {
ret += "\n at ";
ret += loc;
}
return ret;
}
const sg_location &
sg_io_exception::getLocation () const
{
return _location;
}
void
sg_io_exception::setLocation (const sg_location &location)
{
_location = location;
}
sg_io_exception::sg_io_exception(const std::string& message,
const sg_location& location,
const std::string& origin,
bool report)
: sg_exception(message, origin, location, report) {}
////////////////////////////////////////////////////////////////////////
// Implementation of sg_format_exception.
////////////////////////////////////////////////////////////////////////
sg_format_exception::sg_format_exception ()
: sg_exception()
sg_format_exception::sg_format_exception() noexcept
: sg_exception()
{
_text[0] = '\0';
}
sg_format_exception::sg_format_exception (const char* message,
const char* text,
const char* origin)
: sg_exception(message, origin)
sg_format_exception::sg_format_exception(const char* message,
const char* text,
const char* origin,
bool report)
: sg_exception(message, origin, {}, report)
{
setText(text);
}
sg_format_exception::sg_format_exception( const std::string& message,
const std::string& text,
const std::string& origin )
: sg_exception(message, origin)
sg_format_exception::sg_format_exception(const std::string& message,
const std::string& text,
const std::string& origin,
bool report)
: sg_exception(message, origin, {}, report)
{
setText(text.c_str());
}
sg_format_exception::~sg_format_exception ()
{
}
const char*
sg_format_exception::getText () const
sg_format_exception::getText() const noexcept
{
return _text;
}
void
sg_format_exception::setText (const char* text)
void sg_format_exception::setText(const char* text) noexcept
{
if (text) {
strncpy(_text, text, MAX_TEXT_LEN);
@@ -328,26 +288,19 @@ sg_format_exception::setText (const char* text)
// Implementation of sg_range_exception.
////////////////////////////////////////////////////////////////////////
sg_range_exception::sg_range_exception ()
: sg_exception()
{
}
sg_range_exception::sg_range_exception (const char* message,
const char* origin)
: sg_exception(message, origin)
sg_range_exception::sg_range_exception(const char* message,
const char* origin, bool report)
: sg_exception(message, origin, {}, report)
{
}
sg_range_exception::sg_range_exception(const std::string& message,
const std::string& origin)
: sg_exception(message, origin)
const std::string& origin,
bool report)
: sg_exception(message, origin, {}, report)
{
}
sg_range_exception::~sg_range_exception ()
{
}
////////////////////////////////////////////////////////////////////////

View File

@@ -28,23 +28,23 @@ class sg_location
{
public:
enum {max_path = 1024};
sg_location ();
sg_location(const std::string& path, int line = -1, int column = -1);
sg_location(const SGPath& path, int line = -1, int column = -1);
explicit sg_location(const char* path, int line = -1, int column = -1);
sg_location() noexcept;
sg_location(const std::string& path, int line = -1, int column = -1) noexcept;
sg_location(const SGPath& path, int line = -1, int column = -1) noexcept;
explicit sg_location(const char* path, int line = -1, int column = -1) noexcept;
~sg_location() = default;
const char *getPath() const;
int getLine() const;
int getColumn() const;
int getByte() const;
const char* getPath() const noexcept;
int getLine() const noexcept;
int getColumn() const noexcept;
int getByte() const noexcept;
std::string asString() const;
bool isValid() const;
std::string asString() const noexcept;
bool isValid() const noexcept;
private:
void setPath(const char *p);
private:
void setPath(const char* p) noexcept;
char _path[max_path];
int _line;
@@ -60,20 +60,26 @@ class sg_throwable : public std::exception
{
public:
enum {MAX_TEXT_LEN = 1024};
sg_throwable ();
sg_throwable(const char *message, const char *origin = 0,
const sg_location &loc = {});
sg_throwable() noexcept;
sg_throwable(const char* message, const char* origin = 0,
const sg_location& loc = {}, bool report = true) noexcept;
virtual ~sg_throwable ();
virtual const char* getMessage () const;
virtual const std::string getFormattedMessage () const;
virtual void setMessage (const char* message);
virtual const char* getOrigin () const;
virtual void setOrigin (const char *origin);
virtual ~sg_throwable() noexcept = default;
virtual const char* getMessage() const noexcept;
std::string getFormattedMessage() const noexcept;
virtual void setMessage(const char* message) noexcept;
virtual const char* getOrigin() const noexcept;
virtual void setOrigin(const char* origin) noexcept;
virtual const char* what() const noexcept;
private:
sg_location getLocation() const noexcept;
void setLocation(const sg_location& location) noexcept;
private:
char _message[MAX_TEXT_LEN];
char _origin[MAX_TEXT_LEN];
sg_location _location;
};
@@ -90,10 +96,10 @@ private:
class sg_error : public sg_throwable
{
public:
sg_error ();
sg_error (const char* message, const char* origin = 0);
sg_error(const std::string &message, const std::string &origin = {});
virtual ~sg_error ();
sg_error() noexcept = default;
sg_error(const char* message, const char* origin = 0, bool report = true) noexcept;
sg_error(const std::string& message, const std::string& origin = {}, bool report = true) noexcept;
virtual ~sg_error() noexcept = default;
};
@@ -114,12 +120,12 @@ public:
class sg_exception : public sg_throwable
{
public:
sg_exception ();
sg_exception(const char *message, const char *origin = 0,
const sg_location &loc = {});
sg_exception(const std::string &message, const std::string & = {},
const sg_location &loc = {});
virtual ~sg_exception ();
sg_exception() noexcept = default;
sg_exception(const char* message, const char* origin = 0,
const sg_location& loc = {}, bool report = true) noexcept;
sg_exception(const std::string& message, const std::string& = {},
const sg_location& loc = {}, bool report = true) noexcept;
virtual ~sg_exception() noexcept = default;
};
@@ -137,20 +143,15 @@ public:
class sg_io_exception : public sg_exception
{
public:
sg_io_exception ();
sg_io_exception (const char* message, const char* origin = 0);
sg_io_exception (const char* message, const sg_location &location,
const char* origin = 0);
sg_io_exception (const std::string &message, const std::string &origin = "");
sg_io_exception (const std::string &message, const sg_location &location,
const std::string &origin = "");
sg_io_exception() noexcept = default;
sg_io_exception(const char* message, const char* origin = 0, bool report = true);
sg_io_exception(const char* message, const sg_location& location,
const char* origin = 0, bool report = true);
sg_io_exception(const std::string& message, const std::string& origin = {}, bool report = true);
sg_io_exception(const std::string& message, const sg_location& location,
const std::string& origin = {}, bool report = true);
virtual ~sg_io_exception ();
virtual const std::string getFormattedMessage () const;
virtual const sg_location &getLocation () const;
virtual void setLocation (const sg_location &location);
private:
sg_location _location;
virtual ~sg_io_exception() noexcept = default;
};
@@ -168,14 +169,15 @@ private:
class sg_format_exception : public sg_exception
{
public:
sg_format_exception ();
sg_format_exception (const char* message, const char* text,
const char* origin = 0);
sg_format_exception (const std::string& message, const std::string& text,
const std::string& origin = "");
virtual ~sg_format_exception ();
virtual const char* getText () const;
virtual void setText (const char* text);
sg_format_exception() noexcept;
sg_format_exception(const char* message, const char* text,
const char* origin = 0, bool report = true);
sg_format_exception(const std::string& message, const std::string& text,
const std::string& origin = {}, bool report = true);
const char* getText() const noexcept;
void setText(const char* text) noexcept;
private:
char _text[MAX_TEXT_LEN];
};
@@ -193,12 +195,14 @@ private:
class sg_range_exception : public sg_exception
{
public:
sg_range_exception ();
sg_range_exception (const char* message,
const char* origin = 0);
sg_range_exception (const std::string& message,
const std::string& origin = "");
virtual ~sg_range_exception ();
sg_range_exception() noexcept = default;
sg_range_exception(const char* message,
const char* origin = 0,
bool report = true);
sg_range_exception(const std::string& message,
const std::string& origin = {},
bool report = true);
virtual ~sg_range_exception() noexcept = default;
};
using ThrowCallback = std::function<void(

View File

@@ -250,10 +250,15 @@ void
SGSubsystemGroup::init ()
{
assert(_state == State::BIND);
forEach([this](SGSubsystem* s){
this->notifyWillChange(s, State::INIT);
s->init();
this->notifyDidChange(s, State::INIT);
forEach([this](SGSubsystem* s) {
try {
this->notifyWillChange(s, State::INIT);
s->init();
this->notifyDidChange(s, State::INIT);
} catch (std::exception& e) {
simgear::reportError("Caught exception init-ing subsystem " + s->subsystemId() + "\n\t" + e.what());
throw;
}
});
_state = State::INIT;
}
@@ -283,7 +288,15 @@ SGSubsystemGroup::incrementalInit()
const auto m = _members[_initPosition];
SGTimeStamp st;
st.stamp();
const InitStatus memberStatus = m->subsystem->incrementalInit();
InitStatus memberStatus;
try {
memberStatus = m->subsystem->incrementalInit();
} catch (std::exception& e) {
simgear::reportError("Caught exception init-ing subsystem " + m->subsystem->subsystemId() + "\n\t" + e.what());
throw;
}
m->initTime += st.elapsedMSec();
if (memberStatus == INIT_DONE) {
@@ -351,10 +364,15 @@ SGSubsystemGroup::shutdown ()
void
SGSubsystemGroup::bind ()
{
forEach([this](SGSubsystem* s){
this->notifyWillChange(s, State::BIND);
s->bind();
this->notifyDidChange(s, State::BIND);
forEach([this](SGSubsystem* s) {
try {
this->notifyWillChange(s, State::BIND);
s->bind();
this->notifyDidChange(s, State::BIND);
} catch (std::exception& e) {
simgear::reportError("Caught exception binding subsystem " + s->subsystemId() + "\n\t" + e.what());
throw;
}
});
_state = State::BIND;
}

View File

@@ -244,40 +244,43 @@ readXML (istream &input, XMLVisitor &visitor, const string &path)
// FIXME: get proper error string from system
if (!input.good()) {
sg_io_exception ex ("Problem reading file",
sg_location(path,
XML_GetCurrentLineNumber(parser),
XML_GetCurrentColumnNumber(parser)),
"SimGear XML Parser");
visitor.setParser(0);
XML_ParserFree(parser);
throw ex;
sg_io_exception ex("Problem reading file",
sg_location(path,
XML_GetCurrentLineNumber(parser),
XML_GetCurrentColumnNumber(parser)),
"SimGear XML Parser",
false /* don't report */);
visitor.setParser(0);
XML_ParserFree(parser);
throw ex;
}
input.read(buf,16384);
if (!XML_Parse(parser, buf, input.gcount(), false)) {
sg_io_exception ex (XML_ErrorString(XML_GetErrorCode(parser)),
sg_location(path,
XML_GetCurrentLineNumber(parser),
XML_GetCurrentColumnNumber(parser)),
"SimGear XML Parser");
visitor.setParser(0);
XML_ParserFree(parser);
throw ex;
sg_io_exception ex(XML_ErrorString(XML_GetErrorCode(parser)),
sg_location(path,
XML_GetCurrentLineNumber(parser),
XML_GetCurrentColumnNumber(parser)),
"SimGear XML Parser",
false /* don't report */);
visitor.setParser(0);
XML_ParserFree(parser);
throw ex;
}
}
// Verify end of document.
if (!XML_Parse(parser, buf, 0, true)) {
sg_io_exception ex (XML_ErrorString(XML_GetErrorCode(parser)),
sg_location(path,
XML_GetCurrentLineNumber(parser),
XML_GetCurrentColumnNumber(parser)),
"SimGear XML Parser");
visitor.setParser(0);
XML_ParserFree(parser);
throw ex;
sg_io_exception ex(XML_ErrorString(XML_GetErrorCode(parser)),
sg_location(path,
XML_GetCurrentLineNumber(parser),
XML_GetCurrentColumnNumber(parser)),
"SimGear XML Parser",
false /* don't report */);
visitor.setParser(0);
XML_ParserFree(parser);
throw ex;
}
visitor.setParser(0);
@@ -300,8 +303,8 @@ readXML (const SGPath &path, XMLVisitor &visitor)
throw;
}
} else {
throw sg_io_exception("Failed to open file", sg_location(path),
"SimGear XML Parser");
throw sg_io_exception("Failed to open file", sg_location(path),
"SimGear XML Parser", false /* don't report */);
}
input.close();
}
@@ -318,11 +321,12 @@ readXML (const char *buf, const int size, XMLVisitor &visitor)
visitor.startXML();
if (!XML_Parse(parser, buf, size, false)) {
sg_io_exception ex (XML_ErrorString(XML_GetErrorCode(parser)),
sg_location("In-memory XML buffer",
XML_GetCurrentLineNumber(parser),
XML_GetCurrentColumnNumber(parser)),
"SimGear XML Parser");
sg_io_exception ex(XML_ErrorString(XML_GetErrorCode(parser)),
sg_location("In-memory XML buffer",
XML_GetCurrentLineNumber(parser),
XML_GetCurrentColumnNumber(parser)),
"SimGear XML Parser",
false /* don't report */);
XML_ParserFree(parser);
throw ex;
}

View File

@@ -1 +0,0 @@
2020.3.8