Compare commits

...

66 Commits

Author SHA1 Message Date
Automatic Release Builder
e7598df4d3 new version: 2016.2.0 2016-02-17 21:16:33 +01:00
Automatic Release Builder
63e7a1fbb4 new version: 2016.1.1 2016-02-17 21:16:32 +01:00
Torsten Dreyer
951859d8a7 correct user-agent string for terrasync 2016-02-15 16:53:31 +01:00
James Turner
41f40a9a10 Fix misnamed macro.
- should fix TerraSync user-agent.
2016-02-08 09:37:35 +00:00
Rebecca N. Palmer
a6290e367a math: 'void getMaxSubdiv' does not make any sense
Fixes build failure with GCC 6: https://bugs.debian.org/812014
(getMaxSubdiv is currently unused)
2016-02-06 21:16:27 +00:00
James Turner
af0a51930e CMake: don’t export build to build tree
- only export targets to the install tree, since this is
  hopefully compatible with CMake 2.8
2016-02-02 18:33:20 +00:00
James Turner
ccb5d05eb4 Fix headless build for CMake export 2016-01-30 14:29:12 +00:00
James Turner
9d7402242a Work on CMake export of targets. 2016-01-29 23:15:07 +00:00
James Turner
819833a560 VS2013 compile fixes.
- mostly about return type conversions.
2016-01-27 14:02:27 +00:00
Gijs de Rooy
576ff21488 TerraSync log typo 2016-01-20 12:16:14 +01:00
James Turner
b60f8b4989 New log class for terrasync 2016-01-16 15:49:58 -06:00
James Turner
096d625445 Allow use of noreturn attribute with Clang
- other compilers could also be enabled in the future.
2016-01-12 12:48:34 -06:00
James Turner
dad77b3983 Fix a Simgear compile failure. 2016-01-09 09:45:43 -06:00
James Turner
598b64fa95 Linux test_HTTP fixes.
libCurl HTTP unit-test fixes.
2016-01-08 12:17:02 -06:00
James Turner
b5d6aa3fe4 Linux test_HTTP fixes. 2016-01-06 12:57:04 -06:00
James Turner
f32063e6dd Jenkins build fixes. 2016-01-06 00:07:30 -06:00
James Turner
3d9d44cf73 Fix negative loop counts when dt is small. 2016-01-05 23:18:41 -06:00
James Turner
ac84115ac3 Remove obsolete member 2016-01-05 23:17:20 -06:00
James Turner
d58607242e Merge branch 'next' of ssh://git.code.sf.net/p/flightgear/simgear into next 2016-01-05 20:43:25 -06:00
Torsten Dreyer
7afd2be652 Version 2016.1.0 2016-01-05 20:45:11 +01:00
James Turner
f256d45b65 Quiet a debug message. 2016-01-04 13:36:32 -06:00
James Turner
edf15e9f55 Quite some debug output from the materials caches. 2016-01-03 21:51:58 -06:00
James Turner
2bb24f43fb New accessors for variant support. 2016-01-03 20:57:19 -06:00
James Turner
be0447d4c0 Fixes for stalling scenery downloads.
- handle closed connections equivalent to IDLE, for timeout purposes
- if the server closes the socket in WAITING_FOR_RESPONSE state, fail
  the first sent request when restoring.

Note this does not explain why the server sometimes closes the socket
in this way, but at least it now causes a detectable failure.
2016-01-03 11:58:22 -06:00
James Turner
ef7a0dc5a3 Trying to debug HTTP timeouts 2016-01-01 17:17:55 -06:00
Erik Hofman
5d754c0419 Fix a very rare nan where r_earth/position_radius > 1.0 2015-12-29 15:49:12 +01:00
Erik Hofman
1f23fb89c0 Remove the dependency on boost for STANDALONE mode 2015-12-24 14:18:53 +01:00
Erik Hofman
584ee1364f use the proper namespace 2015-12-23 10:36:03 +01:00
Erik Hofman
1e32c24a17 Fix two comparison between signed and unsigned integer warnings 2015-12-11 11:09:39 +01:00
James Turner
20ea55bdbc Set macos-min-version for C files too
Should fix another 10.7 issues (Nasal code is .c)
2015-12-10 14:53:17 -06:00
James Turner
c62b4467b4 Templated helper to retrieve a subsystem
- example of naming a subsystem
2015-12-10 14:52:04 -06:00
Erik Hofman
31095c39cc Make it possible to tie the absolute position to a property 2015-12-10 11:50:20 +01:00
James Turner
05d9d7cae8 On Mac, force setting macon-min-version
- the CMake option seems to be erratic, it works locally but not
  on the Jenkins machine for inexplicable reasons.
2015-12-08 20:42:43 +00:00
James Turner
78a548b861 Expose catalog name directly. 2015-11-29 12:43:20 +00:00
Torsten Dreyer
6be4ad27ee Add fg_root and cwd to the search path for loaded models
ref: http://sourceforge.net/p/flightgear/mailman/message/34650992/
2015-11-27 11:11:42 +01:00
Torsten Dreyer
589c5ba35a SGMaterialAnimation: Better handling of missing texture
Don't retry loading a missing texture on every frame.
Emit a warning message instead and retry on the next
change of the textures name.
2015-11-27 11:09:16 +01:00
James Turner
81d668784a Fix spelling of Find(CURL) 2015-11-24 00:09:19 +00:00
James Turner
75ad5a7e5c Whitespace fixes. 2015-11-23 17:57:46 +00:00
James Turner
3f20a3d2c6 Fix for catalog adding/removing bugs 2015-11-23 17:57:36 +00:00
James Turner
a57e969639 Optional use libCurl as the HTTP client.
Will permit HTTPS for packages in the future, disabled by default
for the moment.
2015-11-22 23:53:46 +00:00
James Turner
23b8c86e78 More whitespace fixes. 2015-11-22 23:53:46 +00:00
James Turner
5c9ca9cbe2 EOL cleanups. 2015-11-22 22:36:54 +00:00
James Turner
5676f96fbf Require Cmake 2.8.11
- drop OldGNUInstallDirs work-around as a result
2015-11-22 22:34:31 +00:00
Rebecca N. Palmer
4104f7d18f SGPath(): make realpath() suitable for fgValidatePath
Handle non-existent files, drop obsolete workaround
2015-11-21 21:35:15 +00:00
Thomas Geymayer
10e6bbc2c5 SubsystemMgr: prevent double delete and use shared pointers. 2015-11-20 12:34:46 +01:00
Stuart Buchanan
21e6dd34b2 QuadTree fix for large buildings.
QuadTree relies on a bounding box to set up correctly.

ProxyNodes don't have a BB until the model is loaded,
causing the QuadTree to collapse if the DB loader can't
keep up with the STG loader.

Fix this by creating a default BB before the model
is loaded.
2015-11-06 21:38:53 +00:00
Erik Hofman
319922f044 Add the option to set the reference name afterwards (but before calling play() 2015-11-05 15:33:06 +01:00
Torsten Dreyer
ff3efaee93 Fix wrong log-class for debug message 2015-11-02 10:56:17 +01:00
Stuart Buchanan
08fb433923 Use quadtree to improve culling of STG objects 2015-10-29 20:07:12 +00:00
Stuart Buchanan
1a752d28a4 Remove max density 10000m for surface lights. 2015-10-22 20:28:37 +01:00
Thomas Geymayer
00a20409f7 Canvas: use weak pointer to protect parent element access.
Using a weak pointer is the best way to ensure no invalid
pointer is used. This also fixes a possible crash in
simgear::canvas::Element::getParentStyle on destructing
canvas elements.
2015-09-30 11:54:19 +02:00
James Turner
3bfd0c872a Avoid duplicate refresh of Catalogs
- also fix duplicate reporting of successful refresh
2015-09-27 23:14:50 -05:00
James Turner
945cf5d963 Improve package extraction cleanup 2015-09-27 20:39:58 -05:00
James Turner
4e40913aef Package support progress
- check the catalog version explicitly when refreshing
- handle packages with distinct dir name / primary ID correctly
  (requires an updated catalog XML format)
2015-09-27 19:42:08 -05:00
Erik Hofman
3bc53474ed Revert previous change, OpenAL-Soft is not ready yet. 2015-09-22 12:36:40 +02:00
Rebecca N. Palmer
28dff1d5ca Use our stdint.hxx, not C++11 cstdint 2015-09-21 22:09:47 +01:00
James Turner
81bfec336c Fix missing include for uint8_t on Linux 2015-09-21 14:55:52 -05:00
James Turner
60a0c51e2b Package support hacking
- rename failure code to status code, and add more to handle
  cancellation.
- change caching of active Installs from Catalog to Root, to clarify
  ownership
- expose download status on Install
- adjust Delegate signatures to pass more information
2015-09-20 19:34:51 -05:00
James Turner
70c5d60564 Drop explicit SDK setting on Mac 2015-09-20 19:30:04 -05:00
James Turner
1b2247103a Fix error case on HTTPClient 2015-09-20 19:28:23 -05:00
www2
a49c3a49d3 chance the WMM epic form 1 jan 2005 to 1 jan 2015 2015-09-02 10:37:01 +02:00
www2
105438fc58 Add Update the World Magnetic Model to 2015.0 2015-09-02 10:37:01 +02:00
Erik Hofman
2910c6a77b Thorsten Renk:
Add a 4th layer to the sun (next to disc, inner halo and outer halo). While the inner/outer halos change with atmosphere conditions, the new layer is supposed to represent the effect of blinding brilliance - ideally it adds a suitable ray structure to the sun. The effect is most prominent in space (where I'm most keen on seeing it admittedly) because there all atmospheric halo effects are absent and we end with a really unrealistic white disc.

Some screenshots and discussion there

http://forum.flightgear.org/viewtopic.php?f=47&t=27216
2015-08-26 12:16:56 +02:00
Erik Hofman
6dd859c75e It looks like the current version of OpenAL-Soft has better Doppler support 2015-08-26 11:29:43 +02:00
Torsten Dreyer
b7c7f66bf3 Fix #1783: repeated error message on console
This downgrades the "file not found" message to a warning.
2015-08-05 09:26:46 +02:00
Torsten Dreyer
c7a60d4dc4 Bump version to 3.7.0 2015-07-27 21:42:17 +02:00
69 changed files with 2305 additions and 1090 deletions

View File

@@ -1,4 +1,4 @@
cmake_minimum_required (VERSION 2.6.4)
cmake_minimum_required (VERSION 2.8.11)
if(COMMAND cmake_policy)
if(POLICY CMP0054)
@@ -14,10 +14,10 @@ include (CheckIncludeFile)
include (CheckLibraryExists)
include (CheckCXXSourceCompiles)
include (CheckCXXCompilerFlag)
include (GenerateExportHeader)
# using 10.7 because boost requires libc++ and 10.6 doesn't include it
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.7)
set(CMAKE_OSX_SYSROOT /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk)
# only relevant for building shared libs but let's set it regardless
set(CMAKE_OSX_RPATH 1)
@@ -80,12 +80,7 @@ endif(NOT CMAKE_BUILD_TYPE)
# Determine name of library installation directory, i.e. "lib" vs "lib64", which
# differs between all Debian-based vs all other Linux distros.
# See cmake bug #11964, http://cmake.org/gitweb?p=cmake.git;a=commit;h=126c993d
# GNUInstallDirs requires CMake >= 2.8.5, use own file for older cmake
if(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
include(GNUInstallDirs)
else(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
include(OldGNUInstallDirs)
endif(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
include(GNUInstallDirs)
message(STATUS "Library installation directory: ${CMAKE_INSTALL_LIBDIR}")
#####################################################################################
@@ -122,6 +117,7 @@ option(ENABLE_RTI "Set to ON to build SimGear with RTI support" OFF)
option(ENABLE_TESTS "Set to OFF to disable building SimGear's test applications" ON)
option(ENABLE_SOUND "Set to OFF to disable building SimGear's sound support" ON)
option(ENABLE_PKGUTIL "Set to ON to build the sg_pkgutil application (default)" ON)
option(ENABLE_CURL "Set to ON to use libCurl as the HTTP client backend" OFF)
if (MSVC)
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} PATH)
@@ -179,6 +175,11 @@ endif (MSVC AND MSVC_3RDPARTY_ROOT)
if(APPLE)
find_library(COCOA_LIBRARY Cocoa)
# this should be handled by setting CMAKE_OSX_DEPLOYMENT_TARGET
# but it's not working reliably, so forcing it for now
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=10.7")
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR
@@ -209,6 +210,11 @@ endif(SIMGEAR_HEADLESS)
find_package(ZLIB REQUIRED)
if (ENABLE_CURL)
find_package(CURL REQUIRED)
message(STATUS "Curl HTTP client: ENABLED")
endif()
if (SYSTEM_EXPAT)
message(STATUS "Requested to use system Expat library, forcing SIMGEAR_SHARED to true")
set(SIMGEAR_SHARED ON)
@@ -374,6 +380,7 @@ include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIR}
${OPENAL_INCLUDE_DIR}
${CURL_INCLUDE_DIRS}
)
add_definitions(-DHAVE_CONFIG_H)
@@ -402,7 +409,8 @@ set(TEST_LIBS_INTERNAL_CORE
${WINSOCK_LIBRARY}
${RT_LIBRARY}
${DL_LIBRARY}
${COCOA_LIBRARY})
${COCOA_LIBRARY}
${CURL_LIBRARIES})
set(TEST_LIBS SimGearCore ${TEST_LIBS_INTERNAL_CORE})
if(NOT SIMGEAR_HEADLESS)
@@ -416,6 +424,40 @@ include_directories(3rdparty/utf8/source)
add_subdirectory(3rdparty)
add_subdirectory(simgear)
#-----------------------------------------------------------------------------
### Export stuff, see https://cmake.org/cmake/help/v3.2/manual/cmake-packages.7.html#creating-packages
#-----------------------------------------------------------------------------
generate_export_header(SimGearCore)
if(NOT SIMGEAR_HEADLESS)
generate_export_header(SimGearScene)
endif()
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfigVersion.cmake"
VERSION ${SIMGEAR_VERSION}
COMPATIBILITY AnyNewerVersion
)
configure_file(SimGearConfig.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfig.cmake"
@ONLY
)
set(ConfigPackageLocation lib/cmake/SimGear)
install(EXPORT SimGearTargets
DESTINATION ${ConfigPackageLocation}
)
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfigVersion.cmake"
DESTINATION ${ConfigPackageLocation}
COMPONENT Devel
)
#-----------------------------------------------------------------------------
### uninstall target
#-----------------------------------------------------------------------------
@@ -425,5 +467,3 @@ CONFIGURE_FILE(
IMMEDIATE @ONLY)
ADD_CUSTOM_TARGET(uninstall
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")

View File

@@ -1,182 +0,0 @@
# - Define GNU standard installation directories
# Provides install directory variables as defined for GNU software:
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
# Inclusion of this module defines the following variables:
# CMAKE_INSTALL_<dir> - destination for files of a given type
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
# where <dir> is one of:
# BINDIR - user executables (bin)
# SBINDIR - system admin executables (sbin)
# LIBEXECDIR - program executables (libexec)
# SYSCONFDIR - read-only single-machine data (etc)
# SHAREDSTATEDIR - modifiable architecture-independent data (com)
# LOCALSTATEDIR - modifiable single-machine data (var)
# LIBDIR - object code libraries (lib or lib64)
# INCLUDEDIR - C header files (include)
# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
# DATAROOTDIR - read-only architecture-independent data root (share)
# DATADIR - read-only architecture-independent data (DATAROOTDIR)
# INFODIR - info documentation (DATAROOTDIR/info)
# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
# MANDIR - man documentation (DATAROOTDIR/man)
# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
# Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION options of
# install() commands for the corresponding file type. If the includer does
# not define a value the above-shown default will be used and the value will
# appear in the cache for editing by the user.
# Each CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed
# from the corresponding destination by prepending (if necessary) the value
# of CMAKE_INSTALL_PREFIX.
#=============================================================================
# Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com>
# Copyright 2011 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
# Installation directories
#
if(NOT DEFINED CMAKE_INSTALL_BINDIR)
set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
endif()
if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
endif()
if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
endif()
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
set(_LIBDIR_DEFAULT "lib")
# Override this default 'lib' with 'lib64' iff:
# - we are on Linux system but NOT cross-compiling
# - we are NOT on debian
# - we are on a 64 bits system
# reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
# Note that the future of multi-arch handling may be even
# more complicated than that: http://wiki.debian.org/Multiarch
if(CMAKE_SYSTEM_NAME MATCHES "Linux"
AND NOT CMAKE_CROSSCOMPILING
AND NOT EXISTS "/etc/debian_version")
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
message(AUTHOR_WARNING
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
"Please enable at least one language before including GNUInstallDirs.")
else()
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(_LIBDIR_DEFAULT "lib64")
endif()
endif()
endif()
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
endif()
if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
endif()
if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
endif()
if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
endif()
#-----------------------------------------------------------------------------
# Values whose defaults are relative to DATAROOTDIR. Store empty values in
# the cache and store the defaults in local variables if the cache values are
# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
if(NOT CMAKE_INSTALL_DATADIR)
set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
endif()
if(NOT CMAKE_INSTALL_INFODIR)
set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
endif()
if(NOT CMAKE_INSTALL_LOCALEDIR)
set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
endif()
if(NOT CMAKE_INSTALL_MANDIR)
set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
endif()
if(NOT CMAKE_INSTALL_DOCDIR)
set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
endif()
#-----------------------------------------------------------------------------
mark_as_advanced(
CMAKE_INSTALL_BINDIR
CMAKE_INSTALL_SBINDIR
CMAKE_INSTALL_LIBEXECDIR
CMAKE_INSTALL_SYSCONFDIR
CMAKE_INSTALL_SHAREDSTATEDIR
CMAKE_INSTALL_LOCALSTATEDIR
CMAKE_INSTALL_LIBDIR
CMAKE_INSTALL_INCLUDEDIR
CMAKE_INSTALL_OLDINCLUDEDIR
CMAKE_INSTALL_DATAROOTDIR
CMAKE_INSTALL_DATADIR
CMAKE_INSTALL_INFODIR
CMAKE_INSTALL_LOCALEDIR
CMAKE_INSTALL_MANDIR
CMAKE_INSTALL_DOCDIR
)
# Result directories
#
foreach(dir
BINDIR
SBINDIR
LIBEXECDIR
SYSCONFDIR
SHAREDSTATEDIR
LOCALSTATEDIR
LIBDIR
INCLUDEDIR
OLDINCLUDEDIR
DATAROOTDIR
DATADIR
INFODIR
LOCALEDIR
MANDIR
DOCDIR
)
if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
else()
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
endif()
endforeach()

16
SimGearConfig.cmake.in Normal file
View File

@@ -0,0 +1,16 @@
include(CMakeFindDependencyMacro)
find_dependency(ZLIB)
find_dependency(Threads)
# OSG
set(SIMGEAR_HEADLESS @SIMGEAR_HEADLESS@)
set(SIMGEAR_SOUND @ENABLE_SOUND@)
# OpenAL isn't a public dependency, so maybe not needed
#if (SIMGEAR_SOUND)
# find_dependency(OpenAL)
#endif()
include("${CMAKE_CURRENT_LIST_DIR}/SimGearTargets.cmake")

View File

@@ -1,7 +1,7 @@
file(WRITE ${PROJECT_BINARY_DIR}/simgear/version.h "#define SIMGEAR_VERSION ${SIMGEAR_VERSION}")
foreach( mylibfolder
foreach( mylibfolder
bucket
bvh
debug
@@ -54,9 +54,11 @@ if(SIMGEAR_SHARED)
set_property(TARGET SimGearCore PROPERTY LINKER_LANGUAGE CXX)
set_property(TARGET SimGearCore PROPERTY VERSION ${SIMGEAR_VERSION})
set_property(TARGET SimGearCore PROPERTY SOVERSION ${SIMGEAR_SOVERSION})
install(TARGETS SimGearCore EXPORT SimGearCoreConfig LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(EXPORT SimGearCoreConfig DESTINATION share/SimGearCore)
install(TARGETS SimGearCore
EXPORT SimGearTargets
LIBRARY DESTINATION
${CMAKE_INSTALL_LIBDIR})
if(NOT SIMGEAR_HEADLESS)
add_library(SimGearScene SHARED ${sceneSources})
set_property(TARGET SimGearScene PROPERTY LINKER_LANGUAGE CXX)
@@ -64,10 +66,12 @@ if(SIMGEAR_SHARED)
set_property(TARGET SimGearScene PROPERTY SOVERSION ${SIMGEAR_SOVERSION})
# EXPORT SimGearSceneConfig
install(TARGETS SimGearScene LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} )
# install(EXPORT SimGearSceneConfig DESTINATION share/SimGearScene)
install(TARGETS SimGearScene
EXPORT SimGearTargets
LIBRARY
DESTINATION ${CMAKE_INSTALL_LIBDIR} )
endif()
else()
message(STATUS "Library building mode: STATIC LIBRARIES")
@@ -90,8 +94,10 @@ else()
endforeach()
add_library(SimGearCore STATIC ${coreSources} ${localExpatSources})
install(TARGETS SimGearCore ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(TARGETS SimGearCore
EXPORT SimGearTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
if(NOT SIMGEAR_HEADLESS)
get_property(FG_GROUPS_SCENE_SOURCES_C GLOBAL PROPERTY FG_GROUPS_SCENE_SOURCES_C)
string(REPLACE "@" ";" groups ${FG_GROUPS_SCENE_SOURCES_C} )
@@ -112,7 +118,9 @@ else()
endforeach()
add_library(SimGearScene STATIC ${sceneSources})
install(TARGETS SimGearScene ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(TARGETS SimGearScene
EXPORT SimGearTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif(NOT SIMGEAR_HEADLESS)
endif(SIMGEAR_SHARED)
@@ -122,7 +130,8 @@ target_link_libraries(SimGearCore
${DL_LIBRARY}
${EXPAT_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${COCOA_LIBRARY})
${COCOA_LIBRARY}
${CURL_LIBRARIES})
if(NOT SIMGEAR_HEADLESS)
target_link_libraries(SimGearScene

View File

@@ -43,7 +43,7 @@ public:
void removeChild(BVHNode* child);
unsigned getNumChildren() const
{ return _children.size(); }
{ return static_cast<unsigned>(_children.size()); }
const BVHNode* getChild(unsigned i) const
{ if (_children.size() <= i) return 0; return _children[i]; }
BVHNode* getChild(unsigned i)

View File

@@ -31,13 +31,13 @@ public:
virtual ~BVHStaticData() {}
unsigned addVertex(const SGVec3f& vertex)
{ _vertices.push_back(vertex); return _vertices.size() - 1; }
{ _vertices.push_back(vertex); return static_cast<unsigned>(_vertices.size() - 1); }
const SGVec3f& getVertex(unsigned i) const
{ return _vertices[i]; }
unsigned addMaterial(const BVHMaterial* material)
{ _materials.push_back(material); return _materials.size() - 1; }
{ _materials.push_back(material); return static_cast<unsigned>(_materials.size() - 1); }
const BVHMaterial* getMaterial(unsigned i) const
{ if (_materials.size() <= i) return 0; return _materials[i]; }

View File

@@ -207,19 +207,6 @@ namespace canvas
//----------------------------------------------------------------------------
Element::~Element()
{
if( !_transform.valid() )
return;
for(unsigned int i = 0; i < _transform->getNumChildren(); ++i)
{
OSGUserData* ud =
static_cast<OSGUserData*>(_transform->getChild(i)->getUserData());
if( ud )
// Ensure parent is cleared to prevent accessing released memory if an
// element somehow survives longer than his parent.
ud->element->_parent = 0;
}
}
//----------------------------------------------------------------------------
@@ -246,7 +233,7 @@ namespace canvas
//----------------------------------------------------------------------------
ElementPtr Element::getParent() const
{
return _parent;
return _parent.lock();
}
//----------------------------------------------------------------------------
@@ -324,8 +311,9 @@ namespace canvas
//----------------------------------------------------------------------------
bool Element::ascend(EventVisitor& visitor)
{
if( _parent )
return _parent->accept(visitor);
ElementPtr parent = getParent();
if( parent )
return parent->accept(visitor);
return true;
}
@@ -374,9 +362,9 @@ namespace canvas
EventPropagationPath path;
path.push_back( EventTarget(this) );
for( Element* parent = _parent;
parent != NULL;
parent = parent->_parent )
for( ElementPtr parent = getParent();
parent.valid();
parent = parent->getParent() )
path.push_front( EventTarget(parent) );
CanvasPtr canvas = _canvas.lock();
@@ -772,7 +760,7 @@ namespace canvas
Element::Element( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent ):
ElementWeakPtr parent ):
PropertyBasedElement(node),
_canvas( canvas ),
_parent( parent ),
@@ -871,11 +859,12 @@ namespace canvas
Element::getParentStyle(const SGPropertyNode* child) const
{
// Try to get value from parent...
if( _parent )
ElementPtr parent = getParent();
if( parent )
{
Style::const_iterator style =
_parent->_style.find(child->getNameString());
if( style != _parent->_style.end() )
parent->_style.find(child->getNameString());
if( style != parent->_style.end() )
return style->second;
}

View File

@@ -232,8 +232,8 @@ namespace canvas
class RelativeScissor;
CanvasWeakPtr _canvas;
Element *_parent;
CanvasWeakPtr _canvas;
ElementWeakPtr _parent;
mutable uint32_t _attributes_dirty;
@@ -256,7 +256,7 @@ namespace canvas
Element( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent );
ElementWeakPtr parent );
/**
* Returns false on first call and true on any successive call. Use to

View File

@@ -70,7 +70,7 @@ namespace canvas
Group::Group( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent ):
ElementWeakPtr parent ):
Element(canvas, node, parent_style, parent)
{
staticInit();

View File

@@ -45,7 +45,7 @@ namespace canvas
Group( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style = Style(),
Element* parent = 0 );
ElementWeakPtr parent = 0 );
virtual ~Group();
ElementPtr createChild( const std::string& type,

View File

@@ -112,7 +112,7 @@ namespace canvas
Image::Image( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent ):
ElementWeakPtr parent ):
Element(canvas, node, parent_style, parent),
_texture(new osg::Texture2D),
_node_src_rect( node->getNode("source", 0, true) ),

View File

@@ -50,7 +50,7 @@ namespace canvas
Image( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style = Style(),
Element* parent = 0 );
ElementWeakPtr parent = 0 );
virtual ~Image();
virtual void update(double dt);

View File

@@ -62,7 +62,7 @@ namespace canvas
Map::Map( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent ):
ElementWeakPtr parent ):
Group(canvas, node, parent_style, parent),
// TODO make projection configurable
_projection(new SansonFlamsteedProjection),

View File

@@ -42,7 +42,7 @@ namespace canvas
Map( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent = 0 );
ElementWeakPtr parent = 0 );
virtual ~Map();
virtual void update(double dt);

View File

@@ -531,7 +531,7 @@ namespace canvas
Path::Path( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent ):
ElementWeakPtr parent ):
Element(canvas, node, parent_style, parent),
_path( new PathDrawable(this) )
{

View File

@@ -36,7 +36,7 @@ namespace canvas
Path( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent = 0 );
ElementWeakPtr parent = 0 );
virtual ~Path();
virtual void update(double dt);

View File

@@ -740,7 +740,7 @@ namespace canvas
Text::Text( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent ):
ElementWeakPtr parent ):
Element(canvas, node, parent_style, parent),
_text( new Text::TextOSG(this) )
{

View File

@@ -40,7 +40,7 @@ namespace canvas
Text( const CanvasWeakPtr& canvas,
const SGPropertyNode_ptr& node,
const Style& parent_style,
Element* parent = 0 );
ElementWeakPtr parent = 0 );
~Text();
void setText(const char* text);

View File

@@ -190,6 +190,12 @@ inline int (isnan)(double r) { return !(r <= 0 || r >= 0); }
# define DEPRECATED
#endif
#if defined(__clang__)
# define SG_NO_RETURN [[noreturn]]
#else
# define SG_NO_RETURN
#endif
//
// No user modifiable definitions beyond here.
//

View File

@@ -32,7 +32,8 @@ typedef enum {
SG_SOUND = 0x00200000,
SG_NAVAID = 0x00400000,
SG_GUI = 0x00800000,
SG_UNDEFD = 0x01000000, // For range checking
SG_TERRASYNC = 0x01000000,
SG_UNDEFD = 0x02000000, // For range checking
SG_ALL = 0xFFFFFFFF
} sgDebugClass;

View File

@@ -71,6 +71,7 @@ const char* debugClassToString(sgDebugClass c)
case SG_SOUND: return "sound";
case SG_NAVAID: return "navaid";
case SG_GUI: return "gui";
case SG_TERRASYNC: return "terrasync";
default: return "unknown";
}
}

View File

@@ -41,7 +41,7 @@ public:
bool load( const SGPath& path );
// stars
inline int getNumStars() const { return _stars.size(); }
inline int getNumStars() const { return static_cast<int>(_stars.size()); }
inline SGVec3d *getStars() { return &(_stars[0]); }
private:

View File

@@ -18,7 +18,6 @@ set(HEADERS
HTTPFileRequest.hxx
HTTPMemoryRequest.hxx
HTTPRequest.hxx
HTTPContentDecode.hxx
DAVMultiStatus.hxx
SVNRepository.hxx
SVNDirectory.hxx
@@ -41,13 +40,17 @@ set(SOURCES
HTTPFileRequest.cxx
HTTPMemoryRequest.cxx
HTTPRequest.cxx
HTTPContentDecode.cxx
DAVMultiStatus.cxx
SVNRepository.cxx
SVNDirectory.cxx
SVNReportParser.cxx
)
if (NOT ENABLE_CURL)
list(APPEND SOURCES HTTPContentDecode.cxx)
list(APPEND HEADERS HTTPContentDecode.hxx)
endif()
simgear_component(io io "${SOURCES}" "${HEADERS}")
if(ENABLE_TESTS)
@@ -70,8 +73,8 @@ add_executable(decode_binobj decode_binobj.cxx)
target_link_libraries(decode_binobj ${TEST_LIBS})
add_executable(test_binobj test_binobj.cxx)
target_link_libraries(test_binobj ${TEST_LIBS})
target_link_libraries(test_binobj ${TEST_LIBS})
add_test(binobj ${EXECUTABLE_OUTPUT_PATH}/test_binobj)
endif(ENABLE_TESTS)

View File

@@ -193,7 +193,7 @@ public:
{
if (tagStack.empty()) {
if (strcmp(name, DAV_MULTISTATUS_TAG)) {
SG_LOG(SG_IO, SG_WARN, "root element is not " <<
SG_LOG(SG_TERRASYNC, SG_WARN, "root element is not " <<
DAV_MULTISTATUS_TAG << ", got:" << name);
} else {
@@ -202,7 +202,7 @@ public:
// not at the root element
if (tagStack.back() == DAV_MULTISTATUS_TAG) {
if (strcmp(name, DAV_RESPONSE_TAG)) {
SG_LOG(SG_IO, SG_WARN, "multistatus child is not response: saw:"
SG_LOG(SG_TERRASYNC, SG_WARN, "multistatus child is not response: saw:"
<< name);
}
}
@@ -362,7 +362,7 @@ void DAVMultiStatus::parseXML(const char* data, int size)
}
if (!XML_Parse(_d->xmlParser, data, size, false)) {
SG_LOG(SG_IO, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
SG_LOG(SG_TERRASYNC, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
<< " at line:" << XML_GetCurrentLineNumber(_d->xmlParser)
<< " column " << XML_GetCurrentColumnNumber(_d->xmlParser));
@@ -376,7 +376,7 @@ void DAVMultiStatus::finishParse()
{
if (_d->parserInited) {
if (!XML_Parse(_d->xmlParser, NULL, 0, true)) {
SG_LOG(SG_IO, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
SG_LOG(SG_TERRASYNC, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
<< " at line:" << XML_GetCurrentLineNumber(_d->xmlParser)
<< " column " << XML_GetCurrentColumnNumber(_d->xmlParser));
_d->valid = false;

File diff suppressed because it is too large Load Diff

View File

@@ -38,15 +38,15 @@ namespace HTTP
// forward decls
class Connection;
class Client
{
public:
Client();
~Client();
void update(int waitTimeout = 0);
void makeRequest(const Request_ptr& r);
/**
@@ -68,44 +68,51 @@ public:
void setUserAgent(const std::string& ua);
void setProxy(const std::string& proxy, int port, const std::string& auth = "");
/**
* Specify the maximum permitted simultaneous connections
* (default value is 1)
*/
void setMaxConnections(unsigned int maxCons);
const std::string& userAgent() const;
const std::string& proxyHost() const;
const std::string& proxyAuth() const;
/**
* predicate, check if at least one connection is active, with at
* least one request active or queued.
*/
bool hasActiveRequests() const;
/**
* crude tracking of bytes-per-second transferred over the socket.
* suitable for user feedback and rough profiling, nothing more.
*/
unsigned int transferRateBytesPerSec() const;
/**
* total bytes downloaded by this HTTP client, for bandwidth usage
* monitoring
*/
uint64_t totalBytesDownloaded() const;
void debugDumpRequests();
private:
// libCurl callbacks
static size_t requestWriteCallback(char *ptr, size_t size, size_t nmemb, void *userdata);
static size_t requestReadCallback(char *ptr, size_t size, size_t nmemb, void *userdata);
static size_t requestHeaderCallback(char *buffer, size_t size, size_t nitems, void *userdata);
void requestFinished(Connection* con);
void receivedBytes(unsigned int count);
friend class Connection;
friend class Request;
class ClientPrivate;
std::auto_ptr<ClientPrivate> d;
};

View File

@@ -133,19 +133,25 @@ void Request::responseStart(const std::string& r)
const int maxSplit = 2; // HTTP/1.1 nnn reason-string
string_list parts = strutils::split(r, NULL, maxSplit);
if (parts.size() != 3) {
throw sg_io_exception("bad HTTP response");
throw sg_io_exception("bad HTTP response:" + r);
}
_responseVersion = decodeHTTPVersion(parts[0]);
_responseStatus = strutils::to_int(parts[1]);
_responseReason = parts[2];
setReadyState(STATUS_RECEIVED);
}
//------------------------------------------------------------------------------
void Request::responseHeader(const std::string& key, const std::string& value)
{
if( key == "connection" )
if( key == "connection" ) {
_willClose = (value.find("close") != std::string::npos);
} else if (key == "content-length") {
int sz = strutils::to_int(value);
setResponseLength(sz);
}
_responseHeaders[key] = value;
}
@@ -207,7 +213,7 @@ std::string Request::scheme() const
if (firstColon > 0) {
return url().substr(0, firstColon);
}
return ""; // couldn't parse scheme
}
@@ -219,20 +225,20 @@ std::string Request::path() const
if (schemeEnd < 0) {
return ""; // couldn't parse scheme
}
int hostEnd = u.find('/', schemeEnd + 3);
if (hostEnd < 0) {
// couldn't parse host, or URL looks like 'http://foo.com' (no trailing '/')
// fixup to root resource path: '/'
return "/";
// couldn't parse host, or URL looks like 'http://foo.com' (no trailing '/')
// fixup to root resource path: '/'
return "/";
}
int query = u.find('?', hostEnd + 1);
if (query < 0) {
// all remainder of URL is path
return u.substr(hostEnd);
}
return u.substr(hostEnd, query - hostEnd);
}
@@ -244,7 +250,7 @@ std::string Request::query() const
if (query < 0) {
return ""; //no query string found
}
return u.substr(query); //includes question mark
}
@@ -319,6 +325,7 @@ unsigned int Request::responseLength() const
//------------------------------------------------------------------------------
void Request::setFailure(int code, const std::string& reason)
{
SG_LOG(SG_IO, SG_WARN, "HTTP request: set failure:" << code << " reason " << reason);
_responseStatus = code;
_responseReason = reason;

View File

@@ -50,6 +50,7 @@ public:
{
UNSENT = 0,
OPENED,
STATUS_RECEIVED,
HEADERS_RECEIVED,
LOADING,
DONE,
@@ -124,19 +125,19 @@ public:
void setBodyData( const SGPropertyNode* data );
virtual void setUrl(const std::string& url);
virtual std::string method() const
{ return _method; }
virtual std::string url() const
{ return _url; }
virtual std::string scheme() const;
virtual std::string path() const;
virtual std::string host() const;
virtual std::string hostAndPort() const;
virtual unsigned short port() const;
virtual std::string query() const;
StringMap const& responseHeaders() const
{ return _responseHeaders; }
@@ -144,13 +145,13 @@ public:
virtual int responseCode() const
{ return _responseStatus; }
virtual std::string responseReason() const
{ return _responseReason; }
void setResponseLength(unsigned int l);
virtual unsigned int responseLength() const;
/**
* Check if request contains body data.
*/
@@ -165,32 +166,32 @@ public:
* Retrieve the size of the request body.
*/
virtual size_t bodyLength() const;
/**
* Retrieve the body data bytes. Will be passed the maximum body bytes
* to return in the buffer, and must return the actual number
* of bytes written.
* of bytes written.
*/
virtual size_t getBodyData(char* s, size_t offset, size_t max_count) const;
/**
* running total of body bytes received so far. Can be used
* to generate a completion percentage, if the response length is
* known.
* known.
*/
unsigned int responseBytesReceived() const
{ return _receivedBodyBytes; }
enum HTTPVersion {
HTTP_VERSION_UNKNOWN = 0,
HTTP_0_x, // 0.9 or similar
HTTP_1_0,
HTTP_1_1
};
HTTPVersion responseVersion() const
{ return _responseVersion; }
ReadyState readyState() const { return _ready_state; }
/**
@@ -226,7 +227,7 @@ private:
friend class Client;
friend class Connection;
friend class ContentDecoder;
Request(const Request&); // = delete;
Request& operator=(const Request&); // = delete;

View File

@@ -96,14 +96,14 @@ void SVNDirectory::parseCache()
LineState lineState = LINESTATE_HREF;
std::ifstream file(p.c_str());
if (!file.is_open()) {
SG_LOG(SG_IO, SG_WARN, "unable to open cache file for reading:" << p);
SG_LOG(SG_TERRASYNC, SG_WARN, "unable to open cache file for reading:" << p);
return;
}
bool doneSelf = false;
file.getline(href, 1024);
if (strcmp(CACHE_VERSION_4_TOKEN, href)) {
SG_LOG(SG_IO, SG_WARN, "invalid cache file [missing header token]:" << p << " '" << href << "'");
SG_LOG(SG_TERRASYNC, SG_WARN, "invalid cache file [missing header token]:" << p << " '" << href << "'");
return;
}
@@ -183,7 +183,7 @@ void SVNDirectory::writeCache()
void SVNDirectory::setBaseUrl(const string& url)
{
if (_parent) {
SG_LOG(SG_IO, SG_ALERT, "setting base URL on non-root directory " << url);
SG_LOG(SG_TERRASYNC, SG_ALERT, "setting base URL on non-root directory " << url);
return;
}
@@ -248,7 +248,7 @@ void SVNDirectory::deleteChildByName(const std::string& nm)
Dir d(path);
bool ok = d.remove(true);
if (!ok) {
SG_LOG(SG_NETWORK, SG_ALERT, "SVNDirectory::deleteChildByName: failed to remove dir:"
SG_LOG(SG_TERRASYNC, SG_ALERT, "SVNDirectory::deleteChildByName: failed to remove dir:"
<< nm << " at path:\n\t" << path);
}
@@ -261,7 +261,7 @@ void SVNDirectory::deleteChildByName(const std::string& nm)
} else {
bool ok = path.remove();
if (!ok) {
SG_LOG(SG_NETWORK, SG_ALERT, "SVNDirectory::deleteChildByName: failed to remove path:" << nm
SG_LOG(SG_TERRASYNC, SG_ALERT, "SVNDirectory::deleteChildByName: failed to remove path:" << nm
<< " at path:\n\t" << path);
}
}

View File

@@ -73,7 +73,7 @@ public:
void updateFailed(HTTP::Request* req, SVNRepository::ResultCode err)
{
SG_LOG(SG_IO, SG_WARN, "SVN: failed to update from:" << req->url()
SG_LOG(SG_TERRASYNC, SG_WARN, "SVN: failed to update from:" << req->url()
<< "\n(repository:" << p->baseUrl() << ")");
isUpdating = false;
status = err;
@@ -120,6 +120,7 @@ namespace { // anonmouse
Request(repo->baseUrl, "PROPFIND"),
_repo(repo)
{
assert(repo);
requestHeader("Depth") = "0";
setBodyData( PROPFIND_REQUEST_BODY,
"application/xml; charset=\"utf-8\"" );
@@ -133,11 +134,13 @@ namespace { // anonmouse
} else if (responseCode() == 404) {
_repo->propFindFailed(this, SVNRepository::SVN_ERROR_NOT_FOUND);
} else {
SG_LOG(SG_IO, SG_WARN, "request for:" << url() <<
SG_LOG(SG_TERRASYNC, SG_WARN, "request for:" << url() <<
" return code " << responseCode());
_repo->propFindFailed(this, SVNRepository::SVN_ERROR_SOCKET);
_repo = NULL;
}
Request::responseHeadersComplete();
}
virtual void onDone()
@@ -228,7 +231,7 @@ protected:
_repo->updateFailed(this, SVNRepository::SVN_ERROR_NOT_FOUND);
_failed = true;
} else {
SG_LOG(SG_IO, SG_WARN, "SVN: request for:" << url() <<
SG_LOG(SG_TERRASYNC, SG_WARN, "SVN: request for:" << url() <<
" got HTTP status " << responseCode());
_repo->updateFailed(this, SVNRepository::SVN_ERROR_HTTP);
_failed = true;
@@ -328,7 +331,7 @@ void SVNRepository::update()
}
if (_d->targetRevision == rootDir()->cachedRevision()) {
SG_LOG(SG_IO, SG_DEBUG, baseUrl() << " in sync at version " << _d->targetRevision);
SG_LOG(SG_TERRASYNC, SG_DEBUG, baseUrl() << " in sync at version " << _d->targetRevision);
_d->isUpdating = false;
return;
}
@@ -372,7 +375,7 @@ void SVNRepoPrivate::propFindComplete(HTTP::Request* req, DAVCollection* c)
void SVNRepoPrivate::propFindFailed(HTTP::Request *req, SVNRepository::ResultCode err)
{
if (err != SVNRepository::SVN_ERROR_NOT_FOUND) {
SG_LOG(SG_IO, SG_WARN, "PropFind failed for:" << req->url());
SG_LOG(SG_TERRASYNC, SG_WARN, "PropFind failed for:" << req->url());
}
isUpdating = false;

View File

@@ -227,6 +227,13 @@ void NetChannel::handleAccept (void) {
void NetChannel::handleError (int error)
{
if (error == EINPROGRESS) {
// this shoudl never happen, because we should use isNonBlocking to check
// such error codes.
SG_LOG(SG_IO, SG_WARN, "Got EINPROGRESS at NetChannel::handleError: suggests broken logic somewhere else");
return; // not an actual error, don't warn
}
// warn about address lookup failures seperately, don't warn again.
// (and we (ab-)use ENOENT to mean 'name not found'.
if (error != ENOENT) {

View File

@@ -3,15 +3,23 @@
#include <iostream>
#include <map>
#include <sstream>
#include <errno.h>
#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/simgear_config.h>
#include "HTTPClient.hxx"
#include "HTTPRequest.hxx"
#include <simgear/io/sg_netChat.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/timing/timestamp.hxx>
#include <simgear/debug/logstream.hxx>
#if defined(ENABLE_CURL)
#include <curl/multi.h>
#endif
using std::cout;
using std::cerr;
@@ -46,7 +54,7 @@ char body2[body2Size];
cerr << "failed:" << #a << endl; \
exit(1); \
}
class TestRequest : public HTTP::Request
{
public:
@@ -54,41 +62,43 @@ public:
bool failed;
string bodyData;
TestRequest(const std::string& url, const std::string method = "GET") :
TestRequest(const std::string& url, const std::string method = "GET") :
HTTP::Request(url, method),
complete(false)
complete(false),
failed(false)
{
}
std::map<string, string> headers;
protected:
virtual void onDone()
{
complete = true;
}
}
virtual void onFail()
{
failed = true;
}
virtual void gotBodyData(const char* s, int n)
{
//std::cout << "got body data:'" << string(s, n) << "'" <<std::endl;
bodyData += string(s, n);
}
virtual void responseHeader(const string& header, const string& value)
{
Request::responseHeader(header, value);
headers[header] = value;
}
};
class TestServerChannel : public NetChat
{
public:
public:
enum State
{
STATE_IDLE = 0,
@@ -96,19 +106,19 @@ public:
STATE_CLOSING,
STATE_REQUEST_BODY
};
TestServerChannel()
{
state = STATE_IDLE;
setTerminator("\r\n");
}
virtual void collectIncomingData(const char* s, int n)
{
buffer += string(s, n);
}
virtual void foundTerminator(void)
{
if (state == STATE_IDLE) {
@@ -118,16 +128,16 @@ public:
cerr << "malformed request:" << buffer << endl;
exit(-1);
}
method = line[0];
path = line[1];
string::size_type queryPos = path.find('?');
if (queryPos != string::npos) {
parseArgs(path.substr(queryPos + 1));
path = path.substr(0, queryPos);
}
httpVersion = line[2];
requestHeaders.clear();
buffer.clear();
@@ -138,10 +148,10 @@ public:
receivedRequestHeaders();
return;
}
string::size_type colonPos = buffer.find(':');
if (colonPos == string::npos) {
cerr << "malformed HTTP response header:" << buffer << endl;
cerr << "test malformed HTTP response header:" << buffer << endl;
buffer.clear();
return;
}
@@ -156,8 +166,8 @@ public:
} else if (state == STATE_CLOSING) {
// ignore!
}
}
}
void parseArgs(const string& argData)
{
string_list argv = strutils::split(argData, "&");
@@ -173,11 +183,10 @@ public:
args[key] = value;
}
}
void receivedRequestHeaders()
{
state = STATE_IDLE;
if (path == "/test1") {
string contentStr(BODY1);
stringstream d;
@@ -205,7 +214,7 @@ public:
} else if (path == "/test_headers") {
COMPARE(requestHeaders["X-Foo"], string("Bar"));
COMPARE(requestHeaders["X-AnotherHeader"], string("A longer value"));
string contentStr(BODY1);
stringstream d;
d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
@@ -235,11 +244,11 @@ public:
if (requestHeaders["Host"] != "www.google.com") {
sendErrorResponse(400, true, "bad destination");
}
if (requestHeaders["Proxy-Authorization"] != string()) {
sendErrorResponse(401, false, "bad auth"); // shouldn't supply auth
sendErrorResponse(401, false, "bad auth, not empty"); // shouldn't supply auth
}
sendBody2();
} else if (path == "http://www.google.com/test3") {
// proxy test
@@ -247,8 +256,28 @@ public:
sendErrorResponse(400, true, "bad destination");
}
if (requestHeaders["Proxy-Authorization"] != "ABCDEF") {
sendErrorResponse(401, false, "bad auth"); // forbidden
string credentials = requestHeaders["Proxy-Authorization"];
if (credentials.substr(0, 5) != "Basic") {
// request basic auth
stringstream d;
d << "HTTP/1.1 " << 407 << " " << reasonForCode(407) << "\r\n";
d << "WWW-Authenticate: Basic real=\"simgear\"\r\n";
d << "\r\n"; // final CRLF to terminate the headers
push(d.str().c_str());
return;
}
std::vector<unsigned char> userAndPass;
strutils::decodeBase64(credentials.substr(6), userAndPass);
std::string decodedUserPass((char*) userAndPass.data(), userAndPass.size());
if (decodedUserPass != "johndoe:swordfish") {
std::map<string, string>::const_iterator it;
for (it = requestHeaders.begin(); it != requestHeaders.end(); ++it) {
cerr << "header:" << it->first << " = " << it->second << endl;
}
sendErrorResponse(401, false, "bad auth, not as set"); // forbidden
}
sendBody2();
@@ -272,6 +301,12 @@ public:
d << contentStr;
push(d.str().c_str());
closeAfterSending();
} else if (path == "/test_abrupt_close") {
// simulate server doing socket close before sending any
// response - this used to cause a TerraSync failure since we
// would get stuck restarting the request
closeAfterSending();
} else if (path == "/test_args") {
if ((args["foo"] != "abc") || (args["bar"] != "1234") || (args["username"] != "johndoe")) {
sendErrorResponse(400, true, "bad arguments");
@@ -291,43 +326,78 @@ public:
sendErrorResponse(400, true, "bad content type");
return;
}
requestContentLength = strutils::to_int(requestHeaders["Content-Length"]);
setByteCount(requestContentLength);
state = STATE_REQUEST_BODY;
} else if ((path == "/test_put") || (path == "/test_create")) {
if (requestHeaders["Content-Type"] != "x-application/foobar") {
cerr << "bad content type: '" << requestHeaders["Content-Type"] << "'" << endl;
sendErrorResponse(400, true, "bad content type");
return;
}
requestContentLength = strutils::to_int(requestHeaders["Content-Length"]);
setByteCount(requestContentLength);
state = STATE_REQUEST_BODY;
} else {
sendErrorResponse(404, false, "");
}
}
void closeAfterSending()
{
state = STATE_CLOSING;
closeWhenDone();
}
void receivedBody()
{
state = STATE_IDLE;
if (method == "POST") {
parseArgs(buffer);
}
if (path == "/test_post") {
if ((args["foo"] != "abc") || (args["bar"] != "1234") || (args["username"] != "johndoe")) {
sendErrorResponse(400, true, "bad arguments");
return;
}
stringstream d;
d << "HTTP/1.1 " << 204 << " " << reasonForCode(204) << "\r\n";
d << "\r\n"; // final CRLF to terminate the headers
push(d.str().c_str());
cerr << "sent 204 response ok" << endl;
} else if (path == "/test_put") {
std::cerr << "sending PUT response" << std::endl;
COMPARE(buffer, BODY3);
stringstream d;
d << "HTTP/1.1 " << 204 << " " << reasonForCode(204) << "\r\n";
d << "\r\n"; // final CRLF to terminate the headers
push(d.str().c_str());
} else if (path == "/test_create") {
std::cerr << "sending create response" << std::endl;
std::string entityStr = "http://localhost:2000/something.txt";
COMPARE(buffer, BODY3);
stringstream d;
d << "HTTP/1.1 " << 201 << " " << reasonForCode(201) << "\r\n";
d << "Location:" << entityStr << "\r\n";
d << "Content-Length:" << entityStr.size() << "\r\n";
d << "\r\n"; // final CRLF to terminate the headers
d << entityStr;
push(d.str().c_str());
} else {
std::cerr << "weird URL " << path << std::endl;
sendErrorResponse(400, true, "bad URL:" + path);
}
buffer.clear();
}
void sendBody2()
{
stringstream d;
@@ -337,32 +407,36 @@ public:
push(d.str().c_str());
bufferSend(body2, body2Size);
}
void sendErrorResponse(int code, bool close, string content)
{
cerr << "sending error " << code << " for " << path << endl;
cerr << "\tcontent:" << content << endl;
stringstream headerData;
headerData << "HTTP/1.1 " << code << " " << reasonForCode(code) << "\r\n";
headerData << "Content-Length:" << content.size() << "\r\n";
headerData << "\r\n"; // final CRLF to terminate the headers
push(headerData.str().c_str());
push(content.c_str());
if (close) {
closeWhenDone();
}
}
string reasonForCode(int code)
string reasonForCode(int code)
{
switch (code) {
case 200: return "OK";
case 201: return "Created";
case 204: return "no content";
case 404: return "not found";
case 407: return "proxy authentication required";
default: return "unknown code";
}
}
State state;
string buffer;
string method;
@@ -376,7 +450,7 @@ public:
class TestServer : public NetChannel
{
simgear::NetChannelPoller _poller;
public:
public:
TestServer()
{
Socket::initSockets();
@@ -384,14 +458,14 @@ public:
open();
bind(NULL, 2000); // localhost, any port
listen(5);
_poller.addChannel(this);
}
virtual ~TestServer()
{
{
}
virtual bool writable (void) { return false ; }
virtual void handleAccept (void)
@@ -401,10 +475,10 @@ public:
//cout << "did accept from " << addr.getHost() << ":" << addr.getPort() << endl;
TestServerChannel* chan = new TestServerChannel();
chan->setHandle(handle);
_poller.addChannel(chan);
}
void poll()
{
_poller.poll();
@@ -419,13 +493,13 @@ void waitForComplete(HTTP::Client* cl, TestRequest* tr)
while (start.elapsedMSec() < 10000) {
cl->update();
testServer.poll();
if (tr->complete) {
return;
}
SGTimeStamp::sleepForMSec(15);
}
cerr << "timed out" << endl;
}
@@ -435,23 +509,24 @@ void waitForFailed(HTTP::Client* cl, TestRequest* tr)
while (start.elapsedMSec() < 10000) {
cl->update();
testServer.poll();
if (tr->failed) {
return;
}
SGTimeStamp::sleepForMSec(15);
}
cerr << "timed out waiting for failure" << endl;
}
int main(int argc, char* argv[])
{
sglog().setLogLevels( SG_ALL, SG_INFO );
HTTP::Client cl;
// force all requests to use the same connection for this test
cl.setMaxConnections(1);
cl.setMaxConnections(1);
// test URL parsing
TestRequest* tr1 = new TestRequest("http://localhost.woo.zar:2000/test1?foo=bar");
COMPARE(tr1->scheme(), "http");
@@ -459,14 +534,14 @@ int main(int argc, char* argv[])
COMPARE(tr1->host(), "localhost.woo.zar");
COMPARE(tr1->port(), 2000);
COMPARE(tr1->path(), "/test1");
TestRequest* tr2 = new TestRequest("http://192.168.1.1/test1/dir/thing/file.png");
COMPARE(tr2->scheme(), "http");
COMPARE(tr2->hostAndPort(), "192.168.1.1");
COMPARE(tr2->host(), "192.168.1.1");
COMPARE(tr2->port(), 80);
COMPARE(tr2->path(), "/test1/dir/thing/file.png");
// basic get request
{
TestRequest* tr = new TestRequest("http://localhost:2000/test1");
@@ -480,12 +555,12 @@ int main(int argc, char* argv[])
COMPARE(tr->responseBytesReceived(), strlen(BODY1));
COMPARE(tr->bodyData, string(BODY1));
}
{
TestRequest* tr = new TestRequest("http://localhost:2000/testLorem");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
waitForComplete(&cl, tr);
COMPARE(tr->responseCode(), 200);
COMPARE(tr->responseReason(), string("OK"));
@@ -493,7 +568,7 @@ int main(int argc, char* argv[])
COMPARE(tr->responseBytesReceived(), strlen(BODY3));
COMPARE(tr->bodyData, string(BODY3));
}
{
TestRequest* tr = new TestRequest("http://localhost:2000/test_args?foo=abc&bar=1234&username=johndoe");
HTTP::Request_ptr own(tr);
@@ -501,9 +576,7 @@ int main(int argc, char* argv[])
waitForComplete(&cl, tr);
COMPARE(tr->responseCode(), 200);
}
cerr << "done args" << endl;
{
TestRequest* tr = new TestRequest("http://localhost:2000/test_headers");
HTTP::Request_ptr own(tr);
@@ -518,12 +591,12 @@ int main(int argc, char* argv[])
COMPARE(tr->responseBytesReceived(), strlen(BODY1));
COMPARE(tr->bodyData, string(BODY1));
}
// larger get request
for (unsigned int i=0; i<body2Size; ++i) {
body2[i] = (i << 4) | (i >> 2);
}
{
TestRequest* tr = new TestRequest("http://localhost:2000/test2");
HTTP::Request_ptr own(tr);
@@ -533,8 +606,8 @@ int main(int argc, char* argv[])
COMPARE(tr->responseBytesReceived(), body2Size);
COMPARE(tr->bodyData, string(body2, body2Size));
}
cerr << "testing chunked" << endl;
cerr << "testing chunked transfer encoding" << endl;
{
TestRequest* tr = new TestRequest("http://localhost:2000/testchunked");
HTTP::Request_ptr own(tr);
@@ -548,7 +621,7 @@ int main(int argc, char* argv[])
// check trailers made it too
COMPARE(tr->headers["x-foobar"], string("wibble"));
}
// test 404
{
TestRequest* tr = new TestRequest("http://localhost:2000/not-found");
@@ -595,15 +668,40 @@ int main(int argc, char* argv[])
}
cout << "done3" << endl;
// test connectToHost failure
/*
{
TestRequest* tr = new TestRequest("http://not.found/something");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
waitForFailed(tr);
COMPARE(tr->responseCode(), -1);
waitForFailed(&cl, tr);
#if defined(ENABLE_CURL)
const int HOST_NOT_FOUND_CODE = CURLE_COULDNT_RESOLVE_HOST;
#else
const int HOST_NOT_FOUND_CODE = ENOENT;
#endif
COMPARE(tr->responseCode(), HOST_NOT_FOUND_CODE);
}
*/
cout << "testing abrupt close" << endl;
// test server-side abrupt close
{
TestRequest* tr = new TestRequest("http://localhost:2000/test_abrupt_close");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
waitForFailed(&cl, tr);
#if defined(ENABLE_CURL)
const int SERVER_NO_DATA_CODE = CURLE_GOT_NOTHING;
#else
const int SERVER_NO_DATA_CODE = 500;
#endif
COMPARE(tr->responseCode(), SERVER_NO_DATA_CODE);
}
cout << "testing proxy close" << endl;
// test proxy
{
cl.setProxy("localhost", 2000);
@@ -615,9 +713,10 @@ int main(int argc, char* argv[])
COMPARE(tr->responseLength(), body2Size);
COMPARE(tr->bodyData, string(body2, body2Size));
}
#if defined(ENABLE_CURL)
{
cl.setProxy("localhost", 2000, "ABCDEF");
cl.setProxy("localhost", 2000, "johndoe:swordfish");
TestRequest* tr = new TestRequest("http://www.google.com/test3");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
@@ -626,81 +725,105 @@ int main(int argc, char* argv[])
COMPARE(tr->responseBytesReceived(), body2Size);
COMPARE(tr->bodyData, string(body2, body2Size));
}
#endif
// pipelining
cout << "testing HTTP 1.1 pipelineing" << endl;
cout << "testing HTTP 1.1 pipelining" << endl;
{
cl.setProxy("", 80);
TestRequest* tr = new TestRequest("http://localhost:2000/test1");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
TestRequest* tr2 = new TestRequest("http://localhost:2000/testLorem");
HTTP::Request_ptr own2(tr2);
cl.makeRequest(tr2);
TestRequest* tr3 = new TestRequest("http://localhost:2000/test1");
HTTP::Request_ptr own3(tr3);
cl.makeRequest(tr3);
waitForComplete(&cl, tr3);
VERIFY(tr->complete);
VERIFY(tr2->complete);
COMPARE(tr->bodyData, string(BODY1));
COMPARE(tr2->responseLength(), strlen(BODY3));
COMPARE(tr2->responseBytesReceived(), strlen(BODY3));
COMPARE(tr2->bodyData, string(BODY3));
COMPARE(tr3->bodyData, string(BODY1));
}
// multiple requests with an HTTP 1.0 server
{
cout << "http 1.0 multiple requests" << endl;
cl.setProxy("", 80);
TestRequest* tr = new TestRequest("http://localhost:2000/test_1_0/A");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
TestRequest* tr2 = new TestRequest("http://localhost:2000/test_1_0/B");
HTTP::Request_ptr own2(tr2);
cl.makeRequest(tr2);
TestRequest* tr3 = new TestRequest("http://localhost:2000/test_1_0/C");
HTTP::Request_ptr own3(tr3);
cl.makeRequest(tr3);
waitForComplete(&cl, tr3);
VERIFY(tr->complete);
VERIFY(tr2->complete);
COMPARE(tr->responseLength(), strlen(BODY1));
COMPARE(tr->responseBytesReceived(), strlen(BODY1));
COMPARE(tr->bodyData, string(BODY1));
COMPARE(tr2->responseLength(), strlen(BODY3));
COMPARE(tr2->responseBytesReceived(), strlen(BODY3));
COMPARE(tr2->bodyData, string(BODY3));
COMPARE(tr3->bodyData, string(BODY1));
}
// POST
{
cout << "POST" << endl;
cout << "testing POST" << endl;
TestRequest* tr = new TestRequest("http://localhost:2000/test_post?foo=abc&bar=1234&username=johndoe", "POST");
tr->setBodyData("", "application/x-www-form-urlencoded");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
waitForComplete(&cl, tr);
COMPARE(tr->responseCode(), 204);
}
// PUT
{
cout << "testing PUT" << endl;
TestRequest* tr = new TestRequest("http://localhost:2000/test_put", "PUT");
tr->setBodyData(BODY3, "x-application/foobar");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
waitForComplete(&cl, tr);
COMPARE(tr->responseCode(), 204);
}
{
cout << "testing PUT create" << endl;
TestRequest* tr = new TestRequest("http://localhost:2000/test_create", "PUT");
tr->setBodyData(BODY3, "x-application/foobar");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
waitForComplete(&cl, tr);
COMPARE(tr->responseCode(), 201);
}
// test_zero_length_content
{
cout << "zero-length-content-response" << endl;
@@ -712,8 +835,8 @@ int main(int argc, char* argv[])
COMPARE(tr->bodyData, string());
COMPARE(tr->responseBytesReceived(), 0);
}
cout << "all tests passed ok" << endl;
return EXIT_SUCCESS;
}

View File

@@ -24,7 +24,7 @@
// Put in some bullet-proofing to handle magnetic and geographic poles.
// 3/28/2000 EAW
//
// Updated coefficient arrays to use the current WMM2005 model,
// Updated coefficient arrays to use the current wmm2005 model,
// (valid between 2005.0 and 2010.0)
// Also removed unused variables and corrected earth radii constants
// to the values for WGS84 and WMM2005.
@@ -36,6 +36,20 @@
//
// 25/10/2006 Wim Van Hoydonck -- wim.van.hoydonck@gmail.com
//
//
// Updated coefficient arrays to use the current WMM2015 model,
// (valid between 2015.0 and 2020.0)
// Also removed unused variables and corrected earth radii constants
// to the values for WGS84 and WMM2015.
// Reference:
// A. Chulliat , S. Macmillan, P. Alken, C. Beggan, M.
// Nair, B. Hamilton, A. Woods, V. Ridley,
// S Maus, and A Thomson, December 2014, The
// US/UK World Magnetic Model for 2015-2020,
// NOAA Technical Report WMM2015_Report.pdf
//
// 18/06/2015 Jean-Paul Anceaux -- j.p.r.anceaux@gmail.com
// The routine uses a spherical harmonic expansion of the magnetic
// potential up to twelfth order, together with its time variation, as
@@ -52,7 +66,7 @@
// the magnetic poles (where it is ill-defined) where the error may reach
// 4 degrees or more.
//
// Variation is undefined at both the geographic and
// Variation is undefined at both the geographic and
// magnetic poles, even though the field itself is well-behaved. To
// avoid the routine blowing up, latitude entries corresponding to
// the geographic poles are slightly offset. At the magnetic poles,
@@ -90,72 +104,72 @@ static const double a = 6378.137; /* semi-major axis (equatorial radius) o
static const double b = 6356.7523142; /* semi-minor axis referenced to the WGS84 ellipsoid */
static const double r_0 = 6371.2; /* standard Earth magnetic reference radius */
static double gnm_wmm2005[13][13] =
static double gnm_wmm2015[13][13] =
{
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-29556.8, -1671.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-2340.6, 3046.9, 1657.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{1335.4, -2305.1, 1246.7, 674.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{919.8, 798.1, 211.3, -379.4, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-227.4, 354.6, 208.7, -136.5, -168.3, -14.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{73.2, 69.7, 76.7, -151.2, -14.9, 14.6, -86.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{80.1, -74.5, -1.4, 38.5, 12.4, 9.5, 5.7, 1.8, 0.0, 0.0, 0.0, 0.0, 0.0},
{24.9, 7.7, -11.6, -6.9, -18.2, 10.0, 9.2, -11.6, -5.2, 0.0, 0.0, 0.0, 0.0},
{5.6, 9.9, 3.5, -7.0, 5.1, -10.8, -1.3, 8.8, -6.7, -9.1, 0.0, 0.0, 0.0},
{-2.3, -6.3, 1.6, -2.6, 0.0, 3.1, 0.4, 2.1, 3.9, -0.1, -2.3, 0.0, 0.0},
{2.8, -1.6, -1.7, 1.7, -0.1, 0.1, -0.7, 0.7, 1.8, 0.0, 1.1, 4.1, 0.0},
{-2.4, -0.4, 0.2, 0.8, -0.3, 1.1, -0.5, 0.4, -0.3, -0.3, -0.1, -0.3, -0.1},
{-29438.5, -1501.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-2445.3, 3012.5, 1676.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{1351.1, -2352.3, 1225.6, 581.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{907.2, 813.7, 120.3, -335.0, 70.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-232.6, 360.1, 192.4, -141.0, -157.4, 4.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{69.5, 67.4, 72.8, -129.8, -29.0, 13.2, -70.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{81.6, -76.1, -6.8, 51.9, 15.0, 9.3, -2.8, 6.7, 0.0, 0.0, 0.0, 0.0, 0.0},
{24.0, 8.6, -16.9, -3.2, -20.6, 13.3, 11.7, -16.0, -2.0, 0.0, 0.0, 0.0, 0.0},
{5.4, 8.8, 3.1, -3.1, 0.6, -13.3, -0.1, 8.7, -9.1, -10.5, 0.0, 0.0, 0.0},
{-1.9, -6.5, 0.2, 0.6, -0.6, 1.7, -0.7, 2.1, 2.3, -1.8, -3.6, 0.0, 0.0},
{3.1, -1.5, -2.3, 2.1, -0.9, 0.6, -0.7, 0.2, 1.7, -0.2, 0.4, 3.5, 0.0},
{-2.0, -0.3, 0.4, 1.3, -0.9, 0.9, 0.1, 0.5, -0.4, -0.4, 0.2, -0.9, 0.0},
};
static double hnm_wmm2005[13][13]=
static double hnm_wmm2015[13][13]=
{
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 5079.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -2594.7, -516.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -199.9, 269.3, -524.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 281.5, -226.0, 145.8, -304.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 42.4, 179.8, -123.0, -19.5, 103.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -20.3, 54.7, 63.6, -63.4, -0.1, 50.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -61.5, -22.4, 7.2, 25.4, 11.0, -26.4, -5.1, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 11.2, -21.0, 9.6, -19.8, 16.1, 7.7, -12.9, -0.2, 0.0, 0.0, 0.0, 0.0},
{0.0, -20.1, 12.9, 12.6, -6.7, -8.1, 8.0, 2.9, -7.9, 6.0, 0.0, 0.0, 0.0},
{0.0, 2.4, 0.2, 4.4, 4.8, -6.5, -1.1, -3.4, -0.8, -2.3, -7.9, 0.0, 0.0},
{0.0, 0.3, 1.2, -0.8, -2.5, 0.9, -0.6, -2.7, -0.9, -1.3, -2.0, -1.2, 0.0},
{0.0, -0.4, 0.3, 2.4, -2.6, 0.6, 0.3, 0.0, 0.0, 0.3, -0.9, -0.4, 0.8},
{0.0, 4796.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -2845.6, -642.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -115.3, 245.0, -538.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 283.4, -188.6, 180.9, -329.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 47.4, 196.9, -119.4, 16.1, 100.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -20.7, 33.2, 58.8, -66.5, 7.3, 62.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -54.1, -19.4, 5.6, 24.4, 3.3, -27.5, -2.3, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 10.2, -18.1, 13.2, -14.6, 16.2, 5.7, -9.1, 2.2, 0.0, 0.0, 0.0, 0.0},
{0.0, -21.6, 10.8, 11.7, -6.8, -6.9, 7.8, 1.0, -3.9, 8.5, 0.0, 0.0, 0.0},
{0.0, 3.3, -0.3, 4.6, 4.4, -7.9, -0.6, -4.1, -2.8, -1.1, -8.7, 0.0, 0.0},
{0.0, -0.1, 2.1, -0.7, -1.1, 0.7, -0.2, -2.1, -1.5, -2.5, -2.0, -2.3, 0.0},
{0.0, -1.0, 0.5, 1.8, -2.2, 0.3, 0.7, -0.1, 0.3, 0.2, -0.9, -0.2, 0.7},
};
static double gtnm_wmm2005[13][13]=
static double gtnm_wmm2015[13][13]=
{
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{8.0, 10.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-15.1, -7.8, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.4, -2.6, -1.2, -6.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-2.5, 2.8, -7.0, 6.2, -3.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-2.8, 0.7, -3.2, -1.1, 0.1, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-0.7, 0.4, -0.3, 2.3, -2.1, -0.6, 1.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.2, -0.1, -0.3, 1.1, 0.6, 0.5, -0.4, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.1, 0.3, -0.4, 0.3, -0.3, 0.2, 0.4, -0.7, 0.4, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{10.7, 17.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-8.6, -3.3, 2.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{3.1, -6.2, -0.4, -10.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-0.4, 0.8, -9.2, 4.0, -4.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-0.2, 0.1, -1.4, 0.0, 1.3, 3.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{-0.5, -0.2, -0.6, 2.4, -1.1, 0.3, 1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.2, -0.2, -0.4, 1.3, 0.2, -0.4, -0.9, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.1, -0.5, 0.5, -0.2, 0.4, 0.2, -0.4, 0.3, 0.0, 0.0, 0.0, 0.0},
{0.0, -0.1, -0.1, 0.4, -0.5, -0.2, 0.1, 0.0, -0.2, -0.1, 0.0, 0.0, 0.0},
{0.0, 0.0, -0.1, 0.3, -0.1, -0.1, -0.1, 0.0, -0.2, -0.1, -0.2, 0.0, 0.0},
{0.0, 0.0, -0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.1, -0.1, 0.0},
{0.1, 0.0, 0.0, 0.1, -0.1, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
};
static double htnm_wmm2005[13][13]=
static double htnm_wmm2015[13][13]=
{
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -20.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -23.2, -14.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 5.0, -7.0, -0.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 2.2, 1.6, 5.8, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 1.7, 2.1, 4.8, -1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -0.6, -1.9, -0.4, -0.5, -0.3, 0.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.6, 0.4, 0.2, 0.3, -0.8, -0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -0.2, 0.1, 0.3, 0.4, 0.1, -0.2, 0.4, 0.4, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -26.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -27.1, -13.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 8.4, -0.4, 2.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -0.6, 5.3, 3.0, -5.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.4, 1.6, -1.1, 3.3, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.0, -2.2, -0.7, 0.1, 1.0, 1.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, 0.7, 0.5, -0.2, -0.1, -0.7, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -0.3, 0.3, 0.3, 0.6, -0.1, -0.2, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0},
{0.0, -0.2, -0.1, -0.2, 0.1, 0.1, 0.0, -0.2, 0.4, 0.3, 0.0, 0.0, 0.0},
{0.0, 0.1, -0.1, 0.0, 0.0, -0.2, 0.1, -0.1, -0.2, 0.1, -0.1, 0.0, 0.0},
{0.0, 0.0, 0.1, 0.0, 0.1, 0.0, 0.0, 0.1, 0.0, -0.1, 0.0, -0.1, 0.0},
{0.0, 0.0, 0.0, -0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
};
static const int nmax = 12;
@@ -174,7 +188,7 @@ static double roots[13][13][2];
unsigned long int yymmdd_to_julian_days( int yy, int mm, int dd )
{
unsigned long jd;
yy = (yy < 50) ? (2000 + yy) : (1900 + yy);
jd = dd - 32075L + 1461L * (yy + 4800L + (mm - 14) / 12 ) / 4;
jd = jd + 367L * (mm - 2 - (mm - 14) / 12*12) / 12;
@@ -182,7 +196,7 @@ unsigned long int yymmdd_to_julian_days( int yy, int mm, int dd )
/* printf("julian date = %d\n", jd ); */
return jd;
}
}
/*
@@ -195,8 +209,8 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
{
/* output field B_r,B_th,B_phi,B_x,B_y,B_z */
int n,m;
/* reference date for current model is 1 januari 2005 */
long date0_wmm2005 = yymmdd_to_julian_days(5,1,1);
/* reference date for current model is 1 januari 2015 */
long date0_wmm2015 = yymmdd_to_julian_days(15,1,1);
double yearfrac,sr,r,theta,c,s,psi,fn,fn_0,B_r,B_theta,B_phi,X,Y,Z;
double sinpsi, cospsi, inv_s;
@@ -215,7 +229,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
/* theta is geocentric co-latitude */
r = h*h + 2.0*h * sr +
(a*a*a*a - ( a*a*a*a - b*b*b*b ) * sinlat*sinlat ) /
(a*a*a*a - ( a*a*a*a - b*b*b*b ) * sinlat*sinlat ) /
(a*a - (a*a - b*b) * sinlat*sinlat );
r = sqrt(r);
@@ -224,7 +238,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
c = cos(theta);
s = sin(theta);
/* protect against zero divide at geographic poles */
inv_s = 1.0 / (s + (s == 0.)*1.0e-8);
inv_s = 1.0 / (s + (s == 0.)*1.0e-8);
/* zero out arrays */
for ( n = 0; n <= nmax; n++ ) {
@@ -283,12 +297,12 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
/* compute Gauss coefficients gnm and hnm of degree n and order m for the desired time
achieved by adjusting the coefficients at time t0 for linear secular variation */
/* WMM2005 */
yearfrac = (dat - date0_wmm2005) / 365.25;
/* WMM2015 */
yearfrac = (dat - date0_wmm2015) / 365.25;
for ( n = 1; n <= nmax; n++ ) {
for ( m = 0; m <= nmax; m++ ) {
gnm[n][m] = gnm_wmm2005[n][m] + yearfrac * gtnm_wmm2005[n][m];
hnm[n][m] = hnm_wmm2005[n][m] + yearfrac * htnm_wmm2005[n][m];
gnm[n][m] = gnm_wmm2015[n][m] + yearfrac * gtnm_wmm2015[n][m];
hnm[n][m] = hnm_wmm2015[n][m] + yearfrac * htnm_wmm2015[n][m];
}
}
@@ -310,7 +324,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
double c2_n=0;
double c3_n=0;
for ( m = 0; m <= n; m++ ) {
double tmp = (gnm[n][m] * cm[m] + hnm[n][m] * sm[m]);
double tmp = (gnm[n][m] * cm[m] + hnm[n][m] * sm[m]);
c1_n=c1_n + tmp * P[n][m];
c2_n=c2_n + tmp * DP[n][m];
c3_n=c3_n + m * (gnm[n][m] * sm[m] - hnm[n][m] * cm[m]) * P[n][m];
@@ -340,7 +354,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
/* find variation in radians */
/* return zero variation at magnetic pole X=Y=0. */
/* E is positive */
return (X != 0. || Y != 0.) ? atan2(Y, X) : (double) 0.;
return (X != 0. || Y != 0.) ? atan2(Y, X) : (double) 0.;
}
@@ -350,7 +364,7 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
/* output field B_r,B_th,B_phi,B_x,B_y,B_z */
int n,m;
/* reference dates */
long date0_wmm2005 = yymmdd_to_julian_days(5,1,1);
long date0_wmm2015 = yymmdd_to_julian_days(5,1,1);
double yearfrac,sr,r,theta,c,s,psi,fn,B_r,B_theta,B_phi,X,Y,Z;
@@ -362,7 +376,7 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
/* theta is geocentric co-latitude */
r = h * h + 2.0*h * sr +
(pow(a,4.0) - (pow(a,4.0) - pow(b,4.0)) * pow(sin(lat),2.0)) /
(pow(a,4.0) - (pow(a,4.0) - pow(b,4.0)) * pow(sin(lat),2.0)) /
(a * a - (a * a - b * b) * pow(sin(lat),2.0));
r = sqrt(r);
@@ -407,12 +421,12 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
}
/* compute gnm, hnm at dat */
/* WMM2005 */
yearfrac = (dat - date0_wmm2005) / 365.25;
/* WMM2015 */
yearfrac = (dat - date0_wmm2015) / 365.25;
for ( n = 1; n <= nmax; n++ ) {
for ( m = 0; m <= nmax; m++ ) {
gnm[n][m] = gnm_wmm2005[n][m] + yearfrac * gtnm_wmm2005[n][m];
hnm[n][m] = hnm_wmm2005[n][m] + yearfrac * htnm_wmm2005[n][m];
gnm[n][m] = gnm_wmm2015[n][m] + yearfrac * gtnm_wmm2015[n][m];
hnm[n][m] = hnm_wmm2015[n][m] + yearfrac * htnm_wmm2015[n][m];
}
}

View File

@@ -154,7 +154,7 @@ public:
static bool isNaN(const T& v)
{
#ifdef HAVE_ISNAN
return isnan(v);
return (isnan(v) != 0);
#elif defined HAVE_STD_ISNAN
return std::isnan(v);
#else

View File

@@ -59,7 +59,7 @@ namespace simgear
}
void setMaxSubdiv( size_t aMaxSubdiv ) { mMaxSubdiv = aMaxSubdiv; }
void getMaxSubdiv() const { return mMaxSubdiv; }
size_t getMaxSubdiv() const { return mMaxSubdiv; }
PointList &pointList() { return mPointList; }
const PointList &pointList() const { return mPointList; }

View File

@@ -67,7 +67,7 @@ SGInterpTable::SGInterpTable( const std::string& file )
while ( in ) {
double ind, dep;
in >> ind >> dep;
in >> skipws;
in >> std::skipws;
_table[ind] = dep;
}
}

View File

@@ -835,25 +835,39 @@ SGPath SGPath::documents(const SGPath& def)
//------------------------------------------------------------------------------
std::string SGPath::realpath() const
{
#if (defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED <= 1050)
// Workaround for Mac OS 10.5. Somehow fgfs crashes on Mac at ::realpath.
// This means relative paths cannot be used on Mac OS <= 10.5
return path;
#else
#if defined(_MSC_VER) /*for MS compilers */ || defined(_WIN32) /*needed for non MS windows compilers like MingW*/
#if defined(_MSC_VER) /*for MS compilers */ || defined(_WIN32) /*needed for non MS windows compilers like MingW*/
// with absPath NULL, will allocate, and ignore length
char *buf = _fullpath( NULL, path.c_str(), _MAX_PATH );
#else
#else
// POSIX
char* buf = ::realpath(path.c_str(), NULL);
#endif
if (!buf)
#endif
if (!buf) // File does not exist: return the realpath it would have if created now
// (needed for fgValidatePath security)
{
SG_LOG(SG_IO, SG_ALERT, "ERROR: The path '" << path << "' does not exist in the file system.");
return path;
if (path.empty()) {
return SGPath(".").realpath(); // current directory
}
std::string this_dir = dir();
if (isAbsolute() && this_dir.empty()) { // top level
this_dir = "/";
}
if (file() == "..") {
this_dir = SGPath(SGPath(this_dir).realpath()).dir();
if (this_dir.empty()) { // invalid path: .. above root
return "";
}
return SGPath(this_dir).realpath(); // use native path separator,
// and handle 'existing/nonexisting/../symlink' paths
}
return SGPath(this_dir).realpath() +
#if defined(_MSC_VER) || defined(_WIN32)
"\\" + file();
#else
"/" + file();
#endif
}
std::string p(buf);
free(buf);
return p;
#endif
}

View File

@@ -63,7 +63,7 @@ std::string redirectUrlForVersion(const std::string& aVersion, SGPropertyNode_pt
return v->getStringValue("url");
}
}
return std::string();
}
@@ -77,8 +77,7 @@ public:
m_owner(aOwner)
{
// refreshing
m_owner->changeStatus(Delegate::FAIL_IN_PROGRESS);
m_owner->changeStatus(Delegate::STATUS_IN_PROGRESS);
}
protected:
@@ -90,8 +89,13 @@ protected:
virtual void onDone()
{
if (responseCode() != 200) {
SG_LOG(SG_GENERAL, SG_ALERT, "catalog download failure:" << m_owner->url());
m_owner->refreshComplete(Delegate::FAIL_DOWNLOAD);
Delegate::StatusCode code = Delegate::FAIL_DOWNLOAD;
SG_LOG(SG_GENERAL, SG_ALERT, "catalog download failure:" << m_owner->url()
<< "\n\t" << responseCode());
if (responseCode() == 404) {
code = Delegate::FAIL_NOT_FOUND;
}
m_owner->refreshComplete(code);
return;
}
@@ -106,7 +110,15 @@ protected:
return;
}
std::string ver(m_owner->root()->catalogVersion());
if (m_owner->root()->catalogVersion() != props->getIntValue("catalog-version")) {
SG_LOG(SG_GENERAL, SG_WARN, "catalog:" << m_owner->url() << " is not version "
<< m_owner->root()->catalogVersion());
m_owner->refreshComplete(Delegate::FAIL_VERSION);
return;
}
std::string ver(m_owner->root()->applicationVersion());
if (!checkVersion(ver, props)) {
SG_LOG(SG_GENERAL, SG_WARN, "downloaded catalog " << m_owner->url() << ", version mismatch:\n\t"
<< props->getStringValue("version") << " vs required " << ver);
@@ -138,7 +150,7 @@ protected:
time(&m_owner->m_retrievedTime);
m_owner->writeTimestamp();
m_owner->refreshComplete(Delegate::CATALOG_REFRESHED);
m_owner->refreshComplete(Delegate::STATUS_REFRESHED);
}
private:
@@ -164,9 +176,7 @@ CatalogRef Catalog::createFromUrl(Root* aRoot, const std::string& aUrl)
{
CatalogRef c = new Catalog(aRoot);
c->m_url = aUrl;
Downloader* dl = new Downloader(c, aUrl);
aRoot->makeHTTPRequest(dl);
c->refresh();
return c;
}
@@ -186,8 +196,8 @@ CatalogRef Catalog::createFromPath(Root* aRoot, const SGPath& aPath)
return NULL;
}
if (!checkVersion(aRoot->catalogVersion(), props)) {
std::string redirect = redirectUrlForVersion(aRoot->catalogVersion(), props);
if (!checkVersion(aRoot->applicationVersion(), props)) {
std::string redirect = redirectUrlForVersion(aRoot->applicationVersion(), props);
if (!redirect.empty()) {
SG_LOG(SG_GENERAL, SG_WARN, "catalog at " << aPath << ", version mismatch:\n\t"
<< "redirecting to alternate URL:" << redirect);
@@ -200,13 +210,18 @@ CatalogRef Catalog::createFromPath(Root* aRoot, const SGPath& aPath)
return NULL;
}
} else {
SG_LOG(SG_GENERAL, SG_INFO, "creating catalog from:" << aPath);
}
CatalogRef c = new Catalog(aRoot);
c->m_installRoot = aPath;
c->parseProps(props); // will set status
c->parseProps(props);
c->parseTimestamp();
// parsed XML ok, mark status as valid
c->changeStatus(Delegate::STATUS_SUCCESS);
return c;
}
@@ -214,7 +229,7 @@ bool Catalog::uninstall()
{
bool ok;
bool atLeastOneFailure = false;
BOOST_FOREACH(PackageRef p, installedPackages()) {
ok = p->existingInstall()->uninstall();
if (!ok) {
@@ -231,9 +246,9 @@ bool Catalog::uninstall()
if (!ok) {
atLeastOneFailure = true;
}
changeStatus(atLeastOneFailure ? Delegate::FAIL_FILESYSTEM
: Delegate::FAIL_SUCCESS);
: Delegate::STATUS_SUCCESS);
return ok;
}
@@ -283,31 +298,31 @@ Catalog::installedPackages() const
return r;
}
InstallRef Catalog::installForPackage(PackageRef pkg) const
{
PackageInstallDict::const_iterator it = m_installed.find(pkg);
if (it == m_installed.end()) {
// check if it exists on disk, create
SGPath p(pkg->pathOnDisk());
if (p.exists()) {
return Install::createFromPath(p, CatalogRef(const_cast<Catalog*>(this)));
}
return NULL;
}
return it->second;
}
void Catalog::refresh()
{
if (m_refreshRequest.valid()) {
// refresh in progress
return;
}
Downloader* dl = new Downloader(this, url());
// will iupdate status to IN_PROGRESS
m_refreshRequest = dl;
// will update status to IN_PROGRESS
m_root->makeHTTPRequest(dl);
m_root->catalogRefreshBegin(this);
}
struct FindById
{
FindById(const std::string &id) : m_id(id) {}
bool operator()(const PackageRef& ref) const
{
return ref->id() == m_id;
}
std::string m_id;
};
void Catalog::parseProps(const SGPropertyNode* aProps)
{
// copy everything except package children?
@@ -321,8 +336,14 @@ void Catalog::parseProps(const SGPropertyNode* aProps)
for (int i = 0; i < nChildren; i++) {
const SGPropertyNode* pkgProps = aProps->getChild(i);
if (strcmp(pkgProps->getName(), "package") == 0) {
PackageRef p = getPackageById(pkgProps->getStringValue("id"));
if (p) {
// can't use getPackageById here becuase the variant dict isn't
// built yet. Instead we need to look at m_packages directly.
PackageList::iterator pit = std::find_if(m_packages.begin(), m_packages.end(),
FindById(pkgProps->getStringValue("id")));
PackageRef p;
if (pit != m_packages.end()) {
p = *pit;
// existing package
p->updateFromProps(pkgProps);
orphans.erase(p); // not an orphan
@@ -372,9 +393,6 @@ void Catalog::parseProps(const SGPropertyNode* aProps)
Dir d(m_installRoot);
d.create(0755);
}
// parsed XML ok, mark status as valid
changeStatus(Delegate::FAIL_SUCCESS);
}
PackageRef Catalog::getPackageById(const std::string& aId) const
@@ -383,11 +401,23 @@ PackageRef Catalog::getPackageById(const std::string& aId) const
// works as expected.
PackageWeakMap::const_iterator it = m_variantDict.find(aId);
if (it == m_variantDict.end())
return NULL;
return PackageRef();
return it->second;
}
PackageRef Catalog::getPackageByPath(const std::string& aPath) const
{
PackageList::const_iterator it;
for (it = m_packages.begin(); it != m_packages.end(); ++it) {
if ((*it)->dirName() == aPath) {
return *it;
}
}
return PackageRef();
}
std::string Catalog::id() const
{
return m_props->getStringValue("id");
@@ -398,6 +428,11 @@ std::string Catalog::url() const
return m_url;
}
std::string Catalog::name() const
{
return getLocalisedString(m_props, "name");
}
std::string Catalog::description() const
{
return getLocalisedString(m_props, "description");
@@ -440,6 +475,10 @@ bool Catalog::needsRefresh() const
std::string Catalog::getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const
{
if (!aRoot) {
return std::string();
}
if (aRoot->hasChild(m_root->getLocale())) {
const SGPropertyNode* localeRoot = aRoot->getChild(m_root->getLocale().c_str());
if (localeRoot->hasChild(aName)) {
@@ -450,37 +489,20 @@ std::string Catalog::getLocalisedString(const SGPropertyNode* aRoot, const char*
return aRoot->getStringValue(aName);
}
void Catalog::refreshComplete(Delegate::FailureCode aReason)
void Catalog::refreshComplete(Delegate::StatusCode aReason)
{
m_root->catalogRefreshComplete(this, aReason);
changeStatus(aReason);
m_refreshRequest.reset();
}
void Catalog::registerInstall(Install* ins)
{
if (!ins || ins->package()->catalog() != this) {
return;
}
m_installed[ins->package()] = ins;
}
void Catalog::unregisterInstall(Install* ins)
{
if (!ins || ins->package()->catalog() != this) {
return;
}
m_installed.erase(ins->package());
}
void Catalog::changeStatus(Delegate::FailureCode newStatus)
void Catalog::changeStatus(Delegate::StatusCode newStatus)
{
if (m_status == newStatus) {
return;
}
m_status = newStatus;
m_root->catalogRefreshStatus(this, newStatus);
m_statusCallbacks(this);
}
@@ -489,7 +511,7 @@ void Catalog::addStatusCallback(const Callback& cb)
m_statusCallbacks.push_back(cb);
}
Delegate::FailureCode Catalog::status() const
Delegate::StatusCode Catalog::status() const
{
return m_status;
}

View File

@@ -30,6 +30,7 @@
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/structure/function_list.hxx>
#include <simgear/io/HTTPRequest.hxx>
#include <simgear/package/Delegate.hxx>
@@ -70,7 +71,7 @@ public:
* uninstall this catalog entirely, including all installed packages
*/
bool uninstall();
/**
* perform a refresh of the catalog contents
*/
@@ -105,11 +106,13 @@ public:
std::string url() const;
std::string name() const;
std::string description() const;
PackageRef getPackageById(const std::string& aId) const;
InstallRef installForPackage(PackageRef pkg) const;
PackageRef getPackageByPath(const std::string& aPath) const;
/**
* test if the catalog data was retrieved longer ago than the
@@ -123,11 +126,11 @@ public:
* access the raw property data in the catalog
*/
SGPropertyNode* properties() const;
Delegate::FailureCode status() const;
Delegate::StatusCode status() const;
typedef boost::function<void(Catalog*)> Callback;
void addStatusCallback(const Callback& cb);
template<class C>
@@ -141,38 +144,30 @@ private:
class Downloader;
friend class Downloader;
friend class Install;
void registerInstall(Install* ins);
void unregisterInstall(Install* ins);
void parseProps(const SGPropertyNode* aProps);
void refreshComplete(Delegate::FailureCode aReason);
void refreshComplete(Delegate::StatusCode aReason);
void parseTimestamp();
void writeTimestamp();
std::string getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const;
void changeStatus(Delegate::FailureCode newStatus);
void changeStatus(Delegate::StatusCode newStatus);
Root* m_root;
SGPropertyNode_ptr m_props;
SGPath m_installRoot;
std::string m_url;
Delegate::FailureCode m_status;
Delegate::StatusCode m_status;
HTTP::Request_ptr m_refreshRequest;
PackageList m_packages;
time_t m_retrievedTime;
typedef std::map<std::string, Package*> PackageWeakMap;
PackageWeakMap m_variantDict;
// important that this is a weak-ref to Installs,
// since it is only cleaned up in the Install destructor
typedef std::map<PackageRef, Install*> PackageInstallDict;
PackageInstallDict m_installed;
function_list<Callback> m_statusCallbacks;
};

View File

@@ -18,15 +18,21 @@
#ifndef SG_PACKAGE_DELEGATE_HXX
#define SG_PACKAGE_DELEGATE_HXX
#include <simgear/misc/stdint.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
namespace simgear
{
namespace pkg
{
class Install;
class Catalog;
typedef SGSharedPtr<Catalog> CatalogRef;
typedef SGSharedPtr<Install> InstallRef;
/**
* package delegate is the mechanism to discover progress / completion /
* errors in packaging steps asynchronously.
@@ -35,41 +41,42 @@ class Delegate
{
public:
typedef enum {
FAIL_SUCCESS = 0, ///< not a failure :)
STATUS_SUCCESS = 0,
FAIL_UNKNOWN = 1,
FAIL_IN_PROGRESS, ///< downloading/installation in progress (not a failure :P)
FAIL_CHECKSUM, ///< package MD5 verificstion failed
FAIL_DOWNLOAD, ///< network issue
FAIL_EXTRACT, ///< package archive failed to extract cleanly
STATUS_IN_PROGRESS, ///< downloading/installation in progress
FAIL_CHECKSUM, ///< package MD5 verificstion failed
FAIL_DOWNLOAD, ///< network issue
FAIL_EXTRACT, ///< package archive failed to extract cleanly
FAIL_FILESYSTEM, ///< unknown filesystem error occurred
FAIL_VERSION, ///< version check mismatch
CATALOG_REFRESHED
} FailureCode;
FAIL_VERSION, ///< version check mismatch
FAIL_NOT_FOUND, ///< package URL returned a 404
STATUS_REFRESHED,
USER_CANCELLED
} StatusCode;
virtual ~Delegate() { }
/**
* invoked when all catalogs have finished refreshing - either successfully
* or with a failure.
* emitted when a catalog refesh completes, either success or failure
* If catalog is null, this means /all/ catalogs have been refreshed
*/
virtual void refreshComplete() = 0;
virtual void catalogRefreshed(CatalogRef, StatusCode aReason) = 0;
virtual void startInstall(InstallRef aInstall) = 0;
virtual void installProgress(InstallRef aInstall, unsigned int aBytes, unsigned int aTotal) = 0;
virtual void finishInstall(InstallRef aInstall, StatusCode aReason) = 0;
/**
* emitted when a catalog fails to refresh, due to a network issue or
* some other failure.
* Notification when catalogs/packages are added or removed
*/
virtual void failedRefresh(Catalog*, FailureCode aReason) = 0;
virtual void startInstall(Install* aInstall) = 0;
virtual void installProgress(Install* aInstall, unsigned int aBytes, unsigned int aTotal) = 0;
virtual void finishInstall(Install* aInstall) = 0;
virtual void failedInstall(Install* aInstall, FailureCode aReason) = 0;
};
virtual void availablePackagesChanged() {}
virtual void dataForThumbnail(const std::string& aThumbnailUrl,
size_t lenth, const uint8_t* bytes) {}
};
} // of namespace pkg
} // of namespace simgear

View File

@@ -24,6 +24,7 @@
#include <simgear/package/md5.h>
#include <simgear/structure/exception.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/package/Catalog.hxx>
#include <simgear/package/Package.hxx>
#include <simgear/package/Root.hxx>
@@ -37,7 +38,7 @@ extern "C" {
}
namespace simgear {
namespace pkg {
class Install::PackageArchiveDownloader : public HTTP::Request
@@ -45,48 +46,87 @@ class Install::PackageArchiveDownloader : public HTTP::Request
public:
PackageArchiveDownloader(InstallRef aOwner) :
HTTP::Request("" /* dummy URL */),
m_owner(aOwner)
m_owner(aOwner),
m_downloaded(0)
{
m_urls = m_owner->package()->downloadUrls();
if (m_urls.empty()) {
throw sg_exception("no package download URLs");
}
// TODO randomise order of m_urls
m_extractPath = aOwner->path().dir();
m_extractPath.append("_DOWNLOAD"); // add some temporary value
m_extractPath.append("_extract_" + aOwner->package()->md5());
// clean up any existing files
Dir d(m_extractPath);
if (d.exists()) {
d.remove(true /* recursive */);
}
}
~PackageArchiveDownloader()
{
// always clean up our extraction dir: if we successfully downloaded
// and installed it will be an empty dir, if we failed it might contain
// (some) of the package files.
Dir d(m_extractPath);
if (d.exists()) {
d.remove(true /* recursive */);
}
}
size_t downloadedBytes() const
{
return m_downloaded;
}
int percentDownloaded() const
{
if (responseLength() <= 0) {
return 0;
}
return (m_downloaded * 100) / responseLength();
}
protected:
virtual std::string url() const
{
return m_urls.front();
}
virtual void responseHeadersComplete()
{
Request::responseHeadersComplete();
Dir d(m_extractPath);
d.create(0755);
d.create(0755);
memset(&m_md5, 0, sizeof(SG_MD5_CTX));
SG_MD5Init(&m_md5);
}
virtual void gotBodyData(const char* s, int n)
{
m_buffer += std::string(s, n);
SG_MD5Update(&m_md5, (unsigned char*) s, n);
m_downloaded = m_buffer.size();
m_owner->installProgress(m_buffer.size(), responseLength());
}
virtual void onDone()
{
if (responseCode() != 200) {
SG_LOG(SG_GENERAL, SG_ALERT, "download failure");
doFailure(Delegate::FAIL_DOWNLOAD);
SG_LOG(SG_GENERAL, SG_ALERT, "download failure:" << responseCode() <<
"\n\t" << url());
Delegate::StatusCode code = Delegate::FAIL_DOWNLOAD;
if (responseCode() == 404) {
code = Delegate::FAIL_NOT_FOUND;
}
doFailure(code);
return;
}
@@ -103,65 +143,79 @@ protected:
doFailure(Delegate::FAIL_CHECKSUM);
return;
}
if (!extractUnzip()) {
SG_LOG(SG_GENERAL, SG_WARN, "zip extraction failed");
doFailure(Delegate::FAIL_EXTRACT);
return;
}
if (m_owner->path().exists()) {
//std::cout << "removing existing path" << std::endl;
Dir destDir(m_owner->path());
destDir.remove(true /* recursive */);
}
m_extractPath.append(m_owner->package()->id());
bool ok = m_extractPath.rename(m_owner->path());
// build a path like /path/to/packages/org.some.catalog/Aircraft/extract_xxxx/MyAircraftDir
SGPath extractedPath = m_extractPath;
extractedPath.append(m_owner->package()->dirName());
// rename it to path/to/packages/org.some.catalog/Aircraft/MyAircraftDir
bool ok = extractedPath.rename(m_owner->path());
if (!ok) {
doFailure(Delegate::FAIL_FILESYSTEM);
return;
}
m_owner->m_revision = m_owner->package()->revision();
m_owner->writeRevisionFile();
m_owner->installResult(Delegate::FAIL_SUCCESS);
m_owner->m_download.reset(); // so isDownloading reports false
m_owner->installResult(Delegate::STATUS_SUCCESS);
}
virtual void onFail()
{
if (responseCode() == -1) {
doFailure(Delegate::USER_CANCELLED);
} else {
doFailure(Delegate::FAIL_DOWNLOAD);
}
}
private:
void extractCurrentFile(unzFile zip, char* buffer, size_t bufferSize)
{
unz_file_info fileInfo;
unzGetCurrentFileInfo(zip, &fileInfo,
buffer, bufferSize,
unzGetCurrentFileInfo(zip, &fileInfo,
buffer, bufferSize,
NULL, 0, /* extra field */
NULL, 0 /* comment field */);
std::string name(buffer);
// no absolute paths, no 'up' traversals
// we could also look for suspicious file extensions here (forbid .dll, .exe, .so)
if ((name[0] == '/') || (name.find("../") != std::string::npos) || (name.find("..\\") != std::string::npos)) {
throw sg_format_exception("Bad zip path", name);
}
if (fileInfo.uncompressed_size == 0) {
// assume it's a directory for now
// since we create parent directories when extracting
// a path, we're done here
return;
}
int result = unzOpenCurrentFile(zip);
if (result != UNZ_OK) {
throw sg_io_exception("opening current zip file failed", sg_location(name));
}
std::ofstream outFile;
bool eof = false;
SGPath path(m_extractPath);
path.append(name);
// create enclosing directory heirarchy as required
Dir parentDir(path.dir());
if (!parentDir.exists()) {
@@ -170,12 +224,12 @@ private:
throw sg_io_exception("failed to create directory heirarchy for extraction", path.c_str());
}
}
outFile.open(path.c_str(), std::ios::binary | std::ios::trunc | std::ios::out);
if (outFile.fail()) {
throw sg_io_exception("failed to open output file for writing", path.c_str());
}
while (!eof) {
int bytes = unzReadCurrentFile(zip, buffer, bufferSize);
if (bytes < 0) {
@@ -186,30 +240,30 @@ private:
outFile.write(buffer, bytes);
}
}
outFile.close();
unzCloseCurrentFile(zip);
}
bool extractUnzip()
{
bool result = true;
zlib_filefunc_def memoryAccessFuncs;
fill_memory_filefunc(&memoryAccessFuncs);
char bufferName[128];
snprintf(bufferName, 128, "%p+%lx", m_buffer.data(), m_buffer.size());
unzFile zip = unzOpen2(bufferName, &memoryAccessFuncs);
const size_t BUFFER_SIZE = 32 * 1024;
void* buf = malloc(BUFFER_SIZE);
try {
int result = unzGoToFirstFile(zip);
if (result != UNZ_OK) {
throw sg_exception("failed to go to first file in archive");
}
while (true) {
extractCurrentFile(zip, (char*) buf, BUFFER_SIZE);
result = unzGoToNextFile(zip);
@@ -222,57 +276,53 @@ private:
} catch (sg_exception& e) {
result = false;
}
free(buf);
unzClose(zip);
return result;
}
void doFailure(Delegate::FailureCode aReason)
void doFailure(Delegate::StatusCode aReason)
{
Dir dir(m_extractPath);
dir.remove(true /* recursive */);
if (m_urls.size() == 1) {
std::cout << "failure:" << aReason << std::endl;
m_owner->installResult(aReason);
return;
if (dir.exists()) {
dir.remove(true /* recursive */);
}
std::cout << "retrying download" << std::endl;
m_urls.erase(m_urls.begin()); // pop first URL
// TODO - try other mirrors
m_owner->m_download.reset(); // ensure we get cleaned up
m_owner->installResult(aReason);
}
InstallRef m_owner;
string_list m_urls;
SG_MD5_CTX m_md5;
std::string m_buffer;
SGPath m_extractPath;
size_t m_downloaded;
};
////////////////////////////////////////////////////////////////////
Install::Install(PackageRef aPkg, const SGPath& aPath) :
m_package(aPkg),
m_path(aPath),
m_download(NULL),
_status(Delegate::FAIL_IN_PROGRESS)
m_status(Delegate::STATUS_IN_PROGRESS)
{
parseRevision();
m_package->catalog()->registerInstall(this);
m_package->catalog()->root()->registerInstall(this);
}
Install::~Install()
{
m_package->catalog()->unregisterInstall(this);
}
InstallRef Install::createFromPath(const SGPath& aPath, CatalogRef aCat)
{
std::string id = aPath.file();
PackageRef pkg = aCat->getPackageById(id);
std::string path = aPath.file();
PackageRef pkg = aCat->getPackageByPath(path);
if (!pkg)
throw sg_exception("no package with id:" + id);
throw sg_exception("no package with path:" + path);
return new Install(pkg, aPath);
}
@@ -284,7 +334,7 @@ void Install::parseRevision()
m_revision = 0;
return;
}
std::ifstream f(revisionFile.c_str(), std::ios::in);
f >> m_revision;
}
@@ -307,7 +357,7 @@ void Install::startUpdate()
if (m_download) {
return; // already active
}
m_download = new PackageArchiveDownloader(this);
m_package->catalog()->root()->makeHTTPRequest(m_download);
m_package->catalog()->root()->startInstall(this);
@@ -320,20 +370,95 @@ bool Install::uninstall()
SG_LOG(SG_GENERAL, SG_ALERT, "package uninstall failed: couldn't remove path " << m_path);
return false;
}
m_package->catalog()->unregisterInstall(this);
m_package->catalog()->root()->unregisterInstall(this);
return true;
}
bool Install::isDownloading() const
{
return (m_download != NULL);
return (m_download.valid());
}
bool Install::isQueued() const
{
return m_package->catalog()->root()->isInstallQueued(const_cast<Install*>(this));
}
int Install::downloadedPercent() const
{
if (!m_download.valid()) {
return -1;
}
PackageArchiveDownloader* dl = static_cast<PackageArchiveDownloader*>(m_download.get());
return dl->percentDownloaded();
}
size_t Install::downloadedBytes() const
{
if (!m_download.valid()) {
return -1;
}
PackageArchiveDownloader* dl = static_cast<PackageArchiveDownloader*>(m_download.get());
return dl->downloadedBytes();
}
void Install::cancelDownload()
{
if (m_download.valid()) {
m_download->abort("User cancelled download");
}
if (m_revision == 0) {
SG_LOG(SG_GENERAL, SG_INFO, "cancel install of package, will unregister");
m_package->catalog()->root()->unregisterInstall(this);
}
m_package->catalog()->root()->cancelDownload(this);
}
struct PathAppender
{
PathAppender(const SGPath& p) : m_path(p) {}
SGPath operator()(const std::string& s) const
{
SGPath p(m_path);
p.append(s);
return p;
}
SGPath m_path;
};
PathList Install::thumbnailPaths() const
{
const string_list& thumbs(m_package->thumbnails());
PathList result;
if (thumbs.empty())
return result;
std::transform(thumbs.begin(), thumbs.end(),
std::back_inserter(result),
PathAppender(m_path));
return result;
}
SGPath Install::primarySetPath() const
{
SGPath setPath(m_path);
std::string ps(m_package->id());
setPath.append(ps + "-set.xml");
return setPath;
}
//------------------------------------------------------------------------------
Install* Install::done(const Callback& cb)
{
if( _status == Delegate::FAIL_SUCCESS )
if( m_status == Delegate::STATUS_SUCCESS )
cb(this);
else
_cb_done.push_back(cb);
@@ -344,8 +469,8 @@ Install* Install::done(const Callback& cb)
//------------------------------------------------------------------------------
Install* Install::fail(const Callback& cb)
{
if( _status != Delegate::FAIL_SUCCESS
&& _status != Delegate::FAIL_IN_PROGRESS )
if( m_status != Delegate::STATUS_SUCCESS
&& m_status != Delegate::STATUS_IN_PROGRESS )
cb(this);
else
_cb_fail.push_back(cb);
@@ -356,7 +481,7 @@ Install* Install::fail(const Callback& cb)
//------------------------------------------------------------------------------
Install* Install::always(const Callback& cb)
{
if( _status != Delegate::FAIL_IN_PROGRESS )
if( m_status != Delegate::STATUS_IN_PROGRESS )
cb(this);
else
_cb_always.push_back(cb);
@@ -372,13 +497,12 @@ Install* Install::progress(const ProgressCallback& cb)
}
//------------------------------------------------------------------------------
void Install::installResult(Delegate::FailureCode aReason)
void Install::installResult(Delegate::StatusCode aReason)
{
if (aReason == Delegate::FAIL_SUCCESS) {
m_package->catalog()->root()->finishInstall(this);
m_package->catalog()->root()->finishInstall(this, aReason);
if (aReason == Delegate::STATUS_SUCCESS) {
_cb_done(this);
} else {
m_package->catalog()->root()->failedInstall(this, aReason);
_cb_fail(this);
}

View File

@@ -21,11 +21,13 @@
#include <vector>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sg_dir.hxx>
#include <simgear/package/Delegate.hxx>
#include <simgear/structure/function_list.hxx>
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/io/HTTPRequest.hxx>
#include <boost/bind.hpp>
@@ -78,6 +80,31 @@ public:
bool isDownloading() const;
bool isQueued() const;
int downloadedPercent() const;
size_t downloadedBytes() const;
/**
* full path to the primary -set.xml file for this install
*/
SGPath primarySetPath() const;
/**
* if a download is in progress, cancel it. If this is the first install
* of the package (as opposed to an update), the install will be cleaned
* up once the last reference is gone.
*/
void cancelDownload();
/**
* return the thumbnails associated with this install, but as locations
* on the file system, not URLs. It is assumed the order of thumbnails
* is consistent with the URLs returned from Package::thumbnailUrls()
*/
PathList thumbnailPaths() const;
/**
* Set the handler to be called when the installation successfully
* completes.
@@ -147,16 +174,16 @@ private:
void parseRevision();
void writeRevisionFile();
void installResult(Delegate::FailureCode aReason);
void installResult(Delegate::StatusCode aReason);
void installProgress(unsigned int aBytes, unsigned int aTotal);
PackageRef m_package;
unsigned int m_revision; ///< revision on disk
SGPath m_path; ///< installation point on disk
PackageArchiveDownloader* m_download;
HTTP::Request_ptr m_download;
Delegate::FailureCode _status;
Delegate::StatusCode m_status;
function_list<Callback> _cb_done,
_cb_fail,

View File

@@ -117,7 +117,7 @@ SGPath Package::pathOnDisk() const
{
SGPath p(m_catalog->installRoot());
p.append("Aircraft");
p.append(id());
p.append(dirName());
return p;
}
@@ -139,7 +139,12 @@ InstallRef Package::install()
InstallRef Package::existingInstall(const InstallCallback& cb) const
{
InstallRef install = m_catalog->installForPackage(const_cast<Package*>(this));
InstallRef install;
try {
install = m_catalog->root()->existingInstallForPackage(const_cast<Package*>(this));
} catch (std::exception& e) {
return InstallRef();
}
if( cb )
{
@@ -162,13 +167,30 @@ std::string Package::qualifiedId() const
return m_catalog->id() + "." + id();
}
std::string Package::qualifiedVariantId(const unsigned int variantIndex) const
{
return m_catalog->id() + "." + variants()[variantIndex];
}
std::string Package::md5() const
{
return m_props->getStringValue("md5");
}
std::string Package::dirName() const
{
std::string r(m_props->getStringValue("dir"));
if (r.empty())
throw sg_exception("missing dir property on catalog package entry for " + m_id);
return r;
}
unsigned int Package::revision() const
{
if (!m_props) {
return 0;
}
return m_props->getIntValue("revision");
}
@@ -200,15 +222,36 @@ SGPropertyNode* Package::properties() const
string_list Package::thumbnailUrls() const
{
string_list r;
if (!m_props) {
return r;
}
BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("thumbnail")) {
r.push_back(dl->getStringValue());
}
return r;
}
string_list Package::thumbnails() const
{
string_list r;
if (!m_props) {
return r;
}
BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("thumbnail-path")) {
r.push_back(dl->getStringValue());
}
return r;
}
string_list Package::downloadUrls() const
{
string_list r;
if (!m_props) {
return r;
}
BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("url")) {
r.push_back(dl->getStringValue());
}
@@ -295,6 +338,20 @@ std::string Package::nameForVariant(const std::string& vid) const
throw sg_exception("Unknow variant +" + vid + " in package " + id());
}
std::string Package::nameForVariant(const unsigned int vIndex) const
{
if (vIndex == 0)
return name();
// offset by minus one to allow for index 0 being the primary
SGPropertyNode_ptr var = m_props->getChild("variant", vIndex - 1);
if (var)
return var->getStringValue("name");
throw sg_exception("Unknow variant in package " + id());
}
} // of namespace pkg
} // of namespace simgear

View File

@@ -75,6 +75,11 @@ public:
* Fully-qualified ID, including our catalog'd ID
*/
std::string qualifiedId() const;
/**
* Fully-qualified ID, including our catalog'd ID
*/
std::string qualifiedVariantId(const unsigned int variantIndex) const;
/**
* human-readable name - note this is probably not localised,
@@ -87,6 +92,8 @@ public:
*/
std::string nameForVariant(const std::string& vid) const;
std::string nameForVariant(const unsigned int vIndex) const;
/**
* syntactic sugar to get the localised description
*/
@@ -122,16 +129,28 @@ public:
string_list thumbnailUrls() const;
/**
* thumbnail file paths within the package on disk
*/
string_list thumbnails() const;
/**
* Packages we depend upon.
* If the dependency list cannot be satisifed for some reason,
* this will raise an sg_exception.
*/
PackageList dependencies() const;
/**
* Name of the package directory on disk. This may or may not be the
* same as the primary ID, depending on the aircraft author
*/
std::string dirName() const;
private:
SGPath pathOnDisk() const;
friend class Catalog;
friend class Root;
Package(const SGPropertyNode* aProps, CatalogRef aCatalog);

View File

@@ -34,45 +34,172 @@
#include <simgear/package/Catalog.hxx>
namespace simgear {
namespace pkg {
typedef std::map<std::string, CatalogRef> CatalogDict;
typedef std::vector<Delegate*> DelegateVec;
typedef std::map<std::string, std::string> MemThumbnailCache;
typedef std::deque<std::string> StringDeque;
class Root::ThumbnailDownloader : public HTTP::Request
{
public:
ThumbnailDownloader(Root::RootPrivate* aOwner, const std::string& aUrl) :
HTTP::Request(aUrl),
m_owner(aOwner)
{
}
protected:
virtual void gotBodyData(const char* s, int n)
{
m_buffer += std::string(s, n);
}
virtual void onDone();
private:
Root::RootPrivate* m_owner;
std::string m_buffer;
};
class Root::RootPrivate
{
public:
RootPrivate() :
http(NULL),
maxAgeSeconds(60 * 60 * 24),
delegate(NULL)
maxAgeSeconds(60 * 60 * 24)
{
}
void fireStartInstall(InstallRef install)
{
DelegateVec::const_iterator it;
for (it = delegates.begin(); it != delegates.end(); ++it) {
(*it)->startInstall(install);
}
}
void fireInstallProgress(InstallRef install,
unsigned int aBytes, unsigned int aTotal)
{
DelegateVec::const_iterator it;
for (it = delegates.begin(); it != delegates.end(); ++it) {
(*it)->installProgress(install, aBytes, aTotal);
}
}
void fireFinishInstall(InstallRef install, Delegate::StatusCode status)
{
DelegateVec::const_iterator it;
for (it = delegates.begin(); it != delegates.end(); ++it) {
(*it)->finishInstall(install, status);
}
}
void fireRefreshStatus(CatalogRef catalog, Delegate::StatusCode status)
{
DelegateVec::const_iterator it;
for (it = delegates.begin(); it != delegates.end(); ++it) {
(*it)->catalogRefreshed(catalog, status);
}
}
void firePackagesChanged()
{
DelegateVec::const_iterator it;
for (it = delegates.begin(); it != delegates.end(); ++it) {
(*it)->availablePackagesChanged();
}
}
void thumbnailDownloadComplete(HTTP::Request_ptr request,
Delegate::StatusCode status, const std::string& bytes)
{
std::string u(request->url());
if (status == Delegate::STATUS_SUCCESS) {
thumbnailCache[u] = bytes;
fireDataForThumbnail(u, bytes);
}
downloadNextPendingThumbnail();
}
void fireDataForThumbnail(const std::string& aUrl, const std::string& bytes)
{
DelegateVec::const_iterator it;
const uint8_t* data = reinterpret_cast<const uint8_t*>(bytes.data());
for (it = delegates.begin(); it != delegates.end(); ++it) {
(*it)->dataForThumbnail(aUrl, bytes.size(), data);
}
}
void downloadNextPendingThumbnail()
{
thumbnailDownloadRequest.clear();
if (pendingThumbnails.empty()) {
return;
}
std::string u = pendingThumbnails.front();
pendingThumbnails.pop_front();
thumbnailDownloadRequest = new Root::ThumbnailDownloader(this, u);
if (http) {
http->makeRequest(thumbnailDownloadRequest);
} else {
httpPendingRequests.push_back(thumbnailDownloadRequest);
}
}
DelegateVec delegates;
SGPath path;
std::string locale;
HTTP::Client* http;
CatalogDict catalogs;
unsigned int maxAgeSeconds;
Delegate* delegate;
std::string version;
std::set<CatalogRef> refreshing;
std::deque<InstallRef> updateDeque;
typedef std::deque<InstallRef> UpdateDeque;
UpdateDeque updateDeque;
std::deque<HTTP::Request_ptr> httpPendingRequests;
HTTP::Request_ptr thumbnailDownloadRequest;
StringDeque pendingThumbnails;
MemThumbnailCache thumbnailCache;
typedef std::map<PackageRef, InstallRef> InstallCache;
InstallCache m_installs;
};
void Root::ThumbnailDownloader::onDone()
{
if (responseCode() != 200) {
SG_LOG(SG_GENERAL, SG_ALERT, "thumbnail download failure:" << url());
m_owner->thumbnailDownloadComplete(this, Delegate::FAIL_DOWNLOAD, std::string());
return;
}
m_owner->thumbnailDownloadComplete(this, Delegate::STATUS_SUCCESS, m_buffer);
//time(&m_owner->m_retrievedTime);
//m_owner->writeTimestamp();
//m_owner->refreshComplete(Delegate::STATUS_REFRESHED);
}
SGPath Root::path() const
{
return d->path;
}
void Root::setMaxAgeSeconds(unsigned int seconds)
{
d->maxAgeSeconds = seconds;
}
unsigned int Root::maxAgeSeconds() const
{
return d->maxAgeSeconds;
@@ -94,10 +221,10 @@ void Root::makeHTTPRequest(HTTP::Request *req)
d->http->makeRequest(req);
return;
}
d->httpPendingRequests.push_back(req);
}
Root::Root(const SGPath& aPath, const std::string& aVersion) :
d(new RootPrivate)
{
@@ -106,13 +233,13 @@ Root::Root(const SGPath& aPath, const std::string& aVersion) :
if (getenv("LOCALE")) {
d->locale = getenv("LOCALE");
}
Dir dir(aPath);
if (!dir.exists()) {
dir.create(0755);
return;
}
BOOST_FOREACH(SGPath c, dir.children(Dir::TYPE_DIR)) {
CatalogRef cat = Catalog::createFromPath(this, c);
if (cat) {
@@ -123,28 +250,33 @@ Root::Root(const SGPath& aPath, const std::string& aVersion) :
Root::~Root()
{
}
std::string Root::catalogVersion() const
int Root::catalogVersion() const
{
return 4;
}
std::string Root::applicationVersion() const
{
return d->version;
}
CatalogRef Root::getCatalogById(const std::string& aId) const
{
CatalogDict::const_iterator it = d->catalogs.find(aId);
if (it == d->catalogs.end()) {
return NULL;
}
return it->second;
}
PackageRef Root::getPackageById(const std::string& aName) const
{
size_t lastDot = aName.rfind('.');
PackageRef pkg = NULL;
if (lastDot == std::string::npos) {
// naked package ID
@@ -155,17 +287,17 @@ PackageRef Root::getPackageById(const std::string& aName) const
return pkg;
}
}
return NULL;
}
std::string catalogId = aName.substr(0, lastDot);
std::string id = aName.substr(lastDot + 1);
std::string id = aName.substr(lastDot + 1);
CatalogRef catalog = getCatalogById(catalogId);
if (!catalog) {
return NULL;
}
return catalog->getPackageById(id);
}
@@ -176,7 +308,21 @@ CatalogList Root::catalogs() const
for (; it != d->catalogs.end(); ++it) {
r.push_back(it->second);
}
return r;
}
PackageList
Root::allPackages() const
{
PackageList r;
CatalogDict::const_iterator it = d->catalogs.begin();
for (; it != d->catalogs.end(); ++it) {
const PackageList& r2(it->second->packages());
r.insert(r.end(), r2.begin(), r2.end());
}
return r;
}
@@ -184,13 +330,13 @@ PackageList
Root::packagesMatching(const SGPropertyNode* aFilter) const
{
PackageList r;
CatalogDict::const_iterator it = d->catalogs.begin();
for (; it != d->catalogs.end(); ++it) {
PackageList r2(it->second->packagesMatching(aFilter));
r.insert(r.end(), r2.begin(), r2.end());
}
return r;
}
@@ -198,31 +344,48 @@ PackageList
Root::packagesNeedingUpdate() const
{
PackageList r;
CatalogDict::const_iterator it = d->catalogs.begin();
for (; it != d->catalogs.end(); ++it) {
PackageList r2(it->second->packagesNeedingUpdate());
r.insert(r.end(), r2.begin(), r2.end());
}
return r;
}
void Root::refresh(bool aForce)
{
bool didStartAny = false;
CatalogDict::iterator it = d->catalogs.begin();
for (; it != d->catalogs.end(); ++it) {
if (aForce || it->second->needsRefresh()) {
it->second->refresh();
didStartAny = true;
}
}
if (!didStartAny) {
// signal refresh complete to the delegate already
d->fireRefreshStatus(CatalogRef(), Delegate::STATUS_REFRESHED);
}
}
void Root::setDelegate(simgear::pkg::Delegate *aDelegate)
void Root::addDelegate(simgear::pkg::Delegate *aDelegate)
{
d->delegate = aDelegate;
d->delegates.push_back(aDelegate);
}
void Root::removeDelegate(simgear::pkg::Delegate *aDelegate)
{
DelegateVec::iterator it = std::find(d->delegates.begin(),
d->delegates.end(), aDelegate);
if (it == d->delegates.end()) {
throw sg_exception("unknown delegate in removeDelegate");
}
d->delegates.erase(it);
}
void Root::setLocale(const std::string& aLocale)
{
d->locale = aLocale;
@@ -238,7 +401,7 @@ void Root::scheduleToUpdate(InstallRef aInstall)
if (!aInstall) {
throw sg_exception("missing argument to scheduleToUpdate");
}
PackageList deps = aInstall->package()->dependencies();
BOOST_FOREACH(Package* dep, deps) {
// will internally schedule for update if required
@@ -248,24 +411,27 @@ void Root::scheduleToUpdate(InstallRef aInstall)
bool wasEmpty = d->updateDeque.empty();
d->updateDeque.push_back(aInstall);
if (wasEmpty) {
aInstall->startUpdate();
}
}
bool Root::isInstallQueued(InstallRef aInstall) const
{
RootPrivate::UpdateDeque::const_iterator it =
std::find(d->updateDeque.begin(), d->updateDeque.end(), aInstall);
return (it != d->updateDeque.end());
}
void Root::startInstall(InstallRef aInstall)
{
if (d->delegate) {
d->delegate->startInstall(aInstall.ptr());
}
d->fireStartInstall(aInstall);
}
void Root::installProgress(InstallRef aInstall, unsigned int aBytes, unsigned int aTotal)
{
if (d->delegate) {
d->delegate->installProgress(aInstall.ptr(), aBytes, aTotal);
}
d->fireInstallProgress(aInstall, aBytes, aTotal);
}
void Root::startNext(InstallRef aCurrent)
@@ -275,45 +441,52 @@ void Root::startNext(InstallRef aCurrent)
} else {
d->updateDeque.pop_front();
}
if (!d->updateDeque.empty()) {
d->updateDeque.front()->startUpdate();
}
}
void Root::finishInstall(InstallRef aInstall)
void Root::finishInstall(InstallRef aInstall, Delegate::StatusCode aReason)
{
if (d->delegate) {
d->delegate->finishInstall(aInstall.ptr());
if (aReason != Delegate::STATUS_SUCCESS) {
SG_LOG(SG_GENERAL, SG_ALERT, "failed to install package:"
<< aInstall->package()->id() << ":" << aReason);
}
// order matters here, so a call to 'isQueued' from a finish-install
// callback returns false, not true
startNext(aInstall);
d->fireFinishInstall(aInstall, aReason);
}
void Root::failedInstall(InstallRef aInstall, Delegate::FailureCode aReason)
void Root::cancelDownload(InstallRef aInstall)
{
SG_LOG(SG_GENERAL, SG_ALERT, "failed to install package:"
<< aInstall->package()->id() << ":" << aReason);
if (d->delegate) {
d->delegate->failedInstall(aInstall.ptr(), aReason);
}
startNext(aInstall);
RootPrivate::UpdateDeque::iterator it =
std::find(d->updateDeque.begin(), d->updateDeque.end(), aInstall);
if (it != d->updateDeque.end()) {
bool startNext = (aInstall == d->updateDeque.front());
d->updateDeque.erase(it);
if (startNext) {
if (!d->updateDeque.empty()) {
d->updateDeque.front()->startUpdate();
}
} // of install was front item
} // of found install in queue
}
void Root::catalogRefreshBegin(CatalogRef aCat)
{
d->refreshing.insert(aCat);
}
void Root::catalogRefreshComplete(CatalogRef aCat, Delegate::FailureCode aReason)
void Root::catalogRefreshStatus(CatalogRef aCat, Delegate::StatusCode aReason)
{
CatalogDict::iterator catIt = d->catalogs.find(aCat->id());
if (aReason != Delegate::FAIL_SUCCESS) {
if (d->delegate) {
d->delegate->failedRefresh(aCat, aReason);
}
d->fireRefreshStatus(aCat, aReason);
if (aReason == Delegate::STATUS_IN_PROGRESS) {
d->refreshing.insert(aCat);
} else {
d->refreshing.erase(aCat);
}
if ((aReason != Delegate::STATUS_REFRESHED) && (aReason != Delegate::STATUS_IN_PROGRESS)) {
// if the failure is permanent, delete the catalog from our
// list (don't touch it on disk)
bool isPermanentFailure = (aReason == Delegate::FAIL_VERSION);
@@ -323,16 +496,16 @@ void Root::catalogRefreshComplete(CatalogRef aCat, Delegate::FailureCode aReason
d->catalogs.erase(catIt);
}
}
} else if (catIt == d->catalogs.end()) {
// first fresh, add to our storage now
}
if ((aReason == Delegate::STATUS_REFRESHED) && (catIt == d->catalogs.end())) {
assert(!aCat->id().empty());
d->catalogs.insert(catIt, CatalogDict::value_type(aCat->id(), aCat));
}
d->refreshing.erase(aCat);
if (d->refreshing.empty()) {
if (d->delegate) {
d->delegate->refreshComplete();
}
d->fireRefreshStatus(CatalogRef(), Delegate::STATUS_REFRESHED);
d->firePackagesChanged();
}
}
@@ -343,21 +516,79 @@ bool Root::removeCatalogById(const std::string& aId)
SG_LOG(SG_GENERAL, SG_WARN, "removeCatalogById: unknown ID:" << aId);
return false;
}
CatalogRef cat = catIt->second;
// drop the reference
d->catalogs.erase(catIt);
bool ok = cat->uninstall();
if (!ok) {
SG_LOG(SG_GENERAL, SG_WARN, "removeCatalogById: catalog :" << aId
<< "failed to uninstall");
}
// notify that a catalog is being removed
d->firePackagesChanged();
return ok;
}
void Root::requestThumbnailData(const std::string& aUrl)
{
MemThumbnailCache::iterator it = d->thumbnailCache.find(aUrl);
if (it == d->thumbnailCache.end()) {
// insert into cache to mark as pending
d->pendingThumbnails.push_front(aUrl);
d->thumbnailCache[aUrl] = std::string();
d->downloadNextPendingThumbnail();
} else if (!it->second.empty()) {
// already loaded, fire data synchronously
d->fireDataForThumbnail(aUrl, it->second);
} else {
// in cache but empty data, still fetching
}
}
InstallRef Root::existingInstallForPackage(PackageRef p) const
{
RootPrivate::InstallCache::const_iterator it =
d->m_installs.find(p);
if (it == d->m_installs.end()) {
// check if it exists on disk, create
SGPath path(p->pathOnDisk());
if (path.exists()) {
// this will add to our cache, and hence, modify m_installs
return Install::createFromPath(path, p->catalog());
}
// insert a null reference into the dictionary, so we don't call
// the pathOnDisk -> exists codepath repeatedley
d->m_installs[p] = InstallRef();
return InstallRef();
}
return it->second;
}
void Root::registerInstall(InstallRef ins)
{
if (!ins.valid()) {
return;
}
d->m_installs[ins->package()] = ins;
}
void Root::unregisterInstall(InstallRef ins)
{
if (!ins .valid()) {
return;
}
d->m_installs.erase(ins->package());
}
} // of namespace pkg
} // of namespace simgear

View File

@@ -62,8 +62,10 @@ public:
void setLocale(const std::string& aLocale);
void setDelegate(Delegate* aDelegate);
void addDelegate(Delegate* aDelegate);
void removeDelegate(Delegate* aDelegate);
std::string getLocale() const;
CatalogList catalogs() const;
@@ -81,17 +83,28 @@ public:
void makeHTTPRequest(HTTP::Request* req);
/**
* the version string of the root. Catalogs must match this version,
* The catalog XML/property version in use. This is used to make incomaptible
* changes to the package/catalog syntax
*/
int catalogVersion() const;
/**
* the version string of the application. Catalogs must match this version,
* or they will be ignored / rejected.
*/
std::string catalogVersion() const;
std::string applicationVersion() const;
/**
* refresh catalogs which are more than the maximum age (24 hours by default)
* set force to true, to download all catalogs regardless of age.
*/
void refresh(bool aForce = false);
/**
*
*/
PackageList allPackages() const;
/**
* retrieve packages matching a filter.
* filter consists of required / minimum values, AND-ed together.
@@ -115,21 +128,33 @@ public:
* from the catalog too.
*/
bool removeCatalogById(const std::string& aId);
/**
* request thumbnail data from the cache / network
*/
void requestThumbnailData(const std::string& aUrl);
bool isInstallQueued(InstallRef aInstall) const;
private:
friend class Install;
friend class Catalog;
friend class Package;
void catalogRefreshBegin(CatalogRef aCat);
void catalogRefreshComplete(CatalogRef aCat, Delegate::FailureCode aReason);
InstallRef existingInstallForPackage(PackageRef p) const;
void catalogRefreshStatus(CatalogRef aCat, Delegate::StatusCode aReason);
void startNext(InstallRef aCurrent);
void startInstall(InstallRef aInstall);
void installProgress(InstallRef aInstall, unsigned int aBytes, unsigned int aTotal);
void finishInstall(InstallRef aInstall);
void failedInstall(InstallRef aInstall, Delegate::FailureCode aReason);
void finishInstall(InstallRef aInstall, Delegate::StatusCode aReason);
void cancelDownload(InstallRef aInstall);
void registerInstall(InstallRef ins);
void unregisterInstall(InstallRef ins);
class ThumbnailDownloader;
class RootPrivate;
std::auto_ptr<RootPrivate> d;
};

View File

@@ -34,22 +34,28 @@ bool keepRunning = true;
class MyDelegate : public pkg::Delegate
{
public:
virtual void refreshComplete()
virtual void catalogRefreshed(pkg::CatalogRef aCatalog, StatusCode aReason)
{
if (aReason == STATUS_REFRESHED) {
if (aCatalog.ptr() == NULL) {
cout << "refreshed all catalogs" << endl;
} else {
cout << "refreshed catalog " << aCatalog->url() << endl;
}
} else if (aReason == STATUS_IN_PROGRESS) {
cout << "started refresh of " << aCatalog->url() << endl;
} else {
cerr << "failed refresh of " << aCatalog->url() << ":" << aReason << endl;
}
}
virtual void failedRefresh(pkg::Catalog* aCatalog, FailureCode aReason)
{
cerr << "failed refresh of " << aCatalog->description() << ":" << aReason << endl;
}
virtual void startInstall(pkg::Install* aInstall)
virtual void startInstall(pkg::InstallRef aInstall)
{
_lastPercent = 999;
cout << "starting install of " << aInstall->package()->name() << endl;
}
virtual void installProgress(pkg::Install* aInstall, unsigned int bytes, unsigned int total)
virtual void installProgress(pkg::InstallRef aInstall, unsigned int bytes, unsigned int total)
{
unsigned int percent = (bytes * 100) / total;
if (percent == _lastPercent) {
@@ -60,15 +66,15 @@ public:
cout << percent << "%" << endl;
}
virtual void finishInstall(pkg::Install* aInstall)
virtual void finishInstall(pkg::InstallRef aInstall, StatusCode aReason)
{
cout << "done install of " << aInstall->package()->name() << endl;
if (aReason == STATUS_SUCCESS) {
cout << "done install of " << aInstall->package()->name() << endl;
} else {
cerr << "failed install of " << aInstall->package()->name() << endl;
}
}
virtual void failedInstall(pkg::Install* aInstall, FailureCode aReason)
{
cerr << "failed install of " << aInstall->package()->name() << endl;
}
private:
unsigned int _lastPercent;
@@ -119,7 +125,7 @@ int main(int argc, char** argv)
pkg::Root* root = new pkg::Root(Dir::current().path(), "");
MyDelegate dlg;
root->setDelegate(&dlg);
root->addDelegate(&dlg);
cout << "Package root is:" << Dir::current().path() << endl;
cout << "have " << root->catalogs().size() << " catalog(s)" << endl;

View File

@@ -11,8 +11,6 @@
#endif
#include "props.hxx"
#include "PropertyInterpolationMgr.hxx"
#include "vectorPropTemplates.hxx"
#include <algorithm>
#include <limits>
@@ -24,31 +22,30 @@
#include <stdio.h>
#include <string.h>
#include <boost/algorithm/string/find_iterator.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/bind.hpp>
#include <boost/functional/hash.hpp>
#include <boost/range.hpp>
#if PROPS_STANDALONE
#include <iostream>
# include <iostream>
using std::cerr;
#else
# include <boost/algorithm/string/find_iterator.hpp>
# include <boost/algorithm/string/predicate.hpp>
# include <boost/algorithm/string/classification.hpp>
# include <boost/bind.hpp>
# include <boost/functional/hash.hpp>
# include <boost/range.hpp>
# include <simgear/compiler.h>
# include <simgear/debug/logstream.hxx>
#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
# include "PropertyInterpolationMgr.hxx"
# include "vectorPropTemplates.hxx"
#if ( _MSC_VER == 1200 )
# if ( _MSC_VER == 1200 )
// MSVC 6 is buggy, and needs something strange here
using std::vector<SGPropertyNode_ptr>;
using std::vector<SGPropertyChangeListener *>;
using std::vector<SGPropertyNode *>;
#endif
# endif
#endif
#if PROPS_STANDALONE
using std::cerr;
#endif
using std::endl;
using std::find;
using std::sort;
@@ -84,6 +81,14 @@ public:
// Local path normalization code.
////////////////////////////////////////////////////////////////////////
#if PROPS_STANDALONE
struct PathComponent
{
string name;
int index;
};
#endif
/**
* Parse the name for a path component.
*
@@ -146,10 +151,149 @@ inline bool validateName(const std::string& name)
return false;
if (!isalpha(name[0]) && name[0] != '_')
return false;
#if PROPS_STANDALONE
std::string is_any_of("_-.");
bool rv = true;
for(unsigned i=1; i<name.length(); ++i) {
if (!isalnum(name[i]) && is_any_of.find(name[i]) == std::string::npos) {
rv = false;
break;
}
}
return rv;
#else
return all(make_iterator_range(name.begin(), name.end()),
is_alnum() || is_any_of("_-."));
#endif
}
#if PROPS_STANDALONE
/**
* Parse the name for a path component.
*
* Name: [_a-zA-Z][-._a-zA-Z0-9]*
*/
static inline const string
parse_name (const string &path, int &i)
{
string name = "";
int max = (int)path.size();
if (path[i] == '.') {
i++;
if (i < max && path[i] == '.') {
i++;
name = "..";
} else {
name = ".";
}
if (i < max && path[i] != '/')
throw string("Illegal character after " + name);
}
else if (isalpha(path[i]) || path[i] == '_') {
name += path[i];
i++;
// The rules inside a name are a little
// less restrictive.
while (i < max) {
if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
path[i] == '-' || path[i] == '.') {
name += path[i];
} else if (path[i] == '[' || path[i] == '/') {
break;
} else {
throw string("name may contain only ._- and alphanumeric characters");
}
i++;
}
}
else {
if (name.size() == 0)
throw string("name must begin with alpha or '_'");
}
return name;
}
/**
* Parse the optional integer index for a path component.
*
* Index: "[" [0-9]+ "]"
*/
static inline int
parse_index (const string &path, int &i)
{
int index = 0;
if (path[i] != '[')
return 0;
else
i++;
for (int max = (int)path.size(); i < max; i++) {
if (isdigit(path[i])) {
index = (index * 10) + (path[i] - '0');
} else if (path[i] == ']') {
i++;
return index;
} else {
break;
}
}
throw string("unterminated index (looking for ']')");
}
/**
* Parse a single path component.
*
* Component: Name Index?
*/
static inline PathComponent
parse_component (const string &path, int &i)
{
PathComponent component;
component.name = parse_name(path, i);
if (component.name[0] != '.')
component.index = parse_index(path, i);
else
component.index = -1;
return component;
}
/**
* Parse a path into its components.
*/
static void
parse_path (const string &path, vector<PathComponent> &components)
{
int pos = 0;
int max = (int)path.size();
// Check for initial '/'
if (path[pos] == '/') {
PathComponent root;
root.name = "";
root.index = -1;
components.push_back(root);
pos++;
while (pos < max && path[pos] == '/')
pos++;
}
while (pos < max) {
components.push_back(parse_component(path, pos));
while (pos < max && path[pos] == '/')
pos++;
}
}
#endif
////////////////////////////////////////////////////////////////////////
// Other static utility functions.
////////////////////////////////////////////////////////////////////////
@@ -182,6 +326,13 @@ static int
find_child (Itr begin, Itr end, int index, const PropertyList& nodes)
{
size_t nNodes = nodes.size();
#if PROPS_STANDALONE
for (int i = 0; i < nNodes; i++) {
SGPropertyNode * node = nodes[i];
if (node->getIndex() == index && compare_strings(node->getName(), begin))
return i;
}
#else
boost::iterator_range<Itr> name(begin, end);
for (size_t i = 0; i < nNodes; i++) {
SGPropertyNode * node = nodes[i];
@@ -191,6 +342,7 @@ find_child (Itr begin, Itr end, int index, const PropertyList& nodes)
if (node->getIndex() == index && boost::equals(node->getName(), name))
return static_cast<int>(i);
}
#endif
return -1;
}
@@ -333,11 +485,57 @@ find_node_aux(SGPropertyNode * current, SplitItr& itr, bool create,
// Internal function for parsing property paths. last_index provides
// and index value for the last node name token, if supplied.
#if PROPS_STANDALONE
static SGPropertyNode *
find_node (SGPropertyNode * current,
const vector<PathComponent> &components,
int position,
bool create)
{
// Run off the end of the list
if (current == 0) {
return 0;
}
// Success! This is the one we want.
else if (position >= (int)components.size()) {
return (current->getAttribute(SGPropertyNode::REMOVED) ? 0 : current);
}
// Empty component means root.
else if (components[position].name == "") {
return find_node(current->getRootNode(), components, position + 1, create);
}
// . means current directory
else if (components[position].name == ".") {
return find_node(current, components, position + 1, create);
}
// .. means parent directory
else if (components[position].name == "..") {
SGPropertyNode * parent = current->getParent();
if (parent == 0)
throw string("Attempt to move past root with '..'");
else
return find_node(parent, components, position + 1, create);
}
// Otherwise, a child name
else {
SGPropertyNode * child =
current->getChild(components[position].name.c_str(),
components[position].index,
create);
return find_node(child, components, position + 1, create);
}
}
#else
template<typename Range>
SGPropertyNode*
find_node (SGPropertyNode * current,
const Range& path,
bool create,
bool create,
int last_index = -1)
{
using namespace boost;
@@ -351,6 +549,7 @@ find_node (SGPropertyNode * current,
else
return find_node_aux(current, itr, create, last_index);
}
#endif
////////////////////////////////////////////////////////////////////////
// Private methods from SGPropertyNode (may be inlined for speed).
@@ -611,13 +810,8 @@ SGPropertyNode::make_string () const
void
SGPropertyNode::trace_write () const
{
#if PROPS_STANDALONE
cerr << "TRACE: Write node " << getPath () << ", value \""
<< make_string() << '"' << endl;
#else
SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
<< ", value \"" << make_string() << '"');
#endif
}
/**
@@ -626,13 +820,8 @@ SGPropertyNode::trace_write () const
void
SGPropertyNode::trace_read () const
{
#if PROPS_STANDALONE
cerr << "TRACE: Write node " << getPath () << ", value \""
<< make_string() << '"' << endl;
#else
SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
<< ", value \"" << make_string() << '"');
#endif
}
////////////////////////////////////////////////////////////////////////
@@ -786,8 +975,6 @@ SGPropertyNode::alias (SGPropertyNode * target)
return true;
}
#if PROPS_STANDALONE
#else
if (!target)
{
SG_LOG(SG_GENERAL, SG_ALERT,
@@ -809,7 +996,6 @@ SGPropertyNode::alias (SGPropertyNode * target)
SG_LOG(SG_GENERAL, SG_ALERT, "Failed to create alias at " << target->getPath() << ". "
"Source " << getPath() << " is a tied property.");
}
#endif
return false;
}
@@ -957,11 +1143,18 @@ SGPropertyNode::getChild (const char * name, int index, bool create)
SGPropertyNode *
SGPropertyNode::getChild (const std::string& name, int index, bool create)
{
#if PROPS_STANDALONE
const char *n = name.c_str();
int pos = find_child(n, n + strlen(n), index, _children);
if (pos >= 0) {
return _children[pos];
#else
SGPropertyNode* node = getExistingChild(name.begin(), name.end(), index);
if (node) {
return node;
#endif
} else if (create) {
node = new SGPropertyNode(name, index, this);
SGPropertyNode* node = new SGPropertyNode(name, index, this);
_children.push_back(node);
fireChildAdded(node);
return node;
@@ -1635,12 +1828,14 @@ SGPropertyNode::setUnspecifiedValue (const char * value)
case props::UNSPECIFIED:
result = set_string(value);
break;
#if !PROPS_STANDALONE
case props::VEC3D:
result = static_cast<SGRawValue<SGVec3d>*>(_value.val)->setValue(parseString<SGVec3d>(value));
break;
case props::VEC4D:
result = static_cast<SGRawValue<SGVec4d>*>(_value.val)->setValue(parseString<SGVec4d>(value));
break;
#endif
case props::NONE:
default:
break;
@@ -1652,6 +1847,7 @@ SGPropertyNode::setUnspecifiedValue (const char * value)
}
//------------------------------------------------------------------------------
#if !PROPS_STANDALONE
bool SGPropertyNode::interpolate( const std::string& type,
const SGPropertyNode& target,
double duration,
@@ -1701,6 +1897,7 @@ simgear::PropertyInterpolationMgr* SGPropertyNode::getInterpolationMgr()
}
simgear::PropertyInterpolationMgr* SGPropertyNode::_interpolation_mgr = 0;
#endif
//------------------------------------------------------------------------------
std::ostream& SGPropertyNode::printOn(std::ostream& stream) const
@@ -1854,20 +2051,37 @@ SGPropertyNode::getRootNode () const
SGPropertyNode *
SGPropertyNode::getNode (const char * relative_path, bool create)
{
#if PROPS_STANDALONE
vector<PathComponent> components;
parse_path(relative_path, components);
return find_node(this, components, 0, create);
#else
using namespace boost;
return find_node(this, make_iterator_range(relative_path, relative_path
+ strlen(relative_path)),
create);
#endif
}
SGPropertyNode *
SGPropertyNode::getNode (const char * relative_path, int index, bool create)
{
#if PROPS_STANDALONE
vector<PathComponent> components;
parse_path(relative_path, components);
if (components.size() > 0)
components.back().index = index;
return find_node(this, components, 0, create);
#else
using namespace boost;
return find_node(this, make_iterator_range(relative_path, relative_path
+ strlen(relative_path)),
create, index);
#endif
}
const SGPropertyNode *
@@ -2315,6 +2529,7 @@ SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
_properties.erase(it);
}
#if !PROPS_STANDALONE
template<>
std::ostream& SGRawBase<SGVec3d>::printOn(std::ostream& stream) const
{
@@ -2351,9 +2566,11 @@ std::ostream& SGRawBase<SGVec4d>::printOn(std::ostream& stream) const
}
return stream;
}
#endif
namespace simgear
{
#if !PROPS_STANDALONE
template<>
std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
{
@@ -2362,6 +2579,7 @@ std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
}
return stream;
}
#endif
namespace
{
@@ -2389,10 +2607,12 @@ bool compareNodeValue(const SGPropertyNode& lhs, const SGPropertyNode& rhs)
case props::STRING:
case props::UNSPECIFIED:
return !strcmp(lhs.getStringValue(), rhs.getStringValue());
#if !PROPS_STANDALONE
case props::VEC3D:
return lhs.getValue<SGVec3d>() == rhs.getValue<SGVec3d>();
case props::VEC4D:
return lhs.getValue<SGVec4d>() == rhs.getValue<SGVec4d>();
#endif
default:
return false;
}
@@ -2449,10 +2669,10 @@ struct PropertyPlaceLess {
}
};
#if !PROPS_STANDALONE
size_t hash_value(const SGPropertyNode& node)
{
using namespace boost;
if (node.nChildren() == 0) {
switch (node.getType()) {
case props::NONE:
@@ -2503,5 +2723,6 @@ size_t hash_value(const SGPropertyNode& node)
return seed;
}
}
#endif
// end of props.cxx

View File

@@ -22,24 +22,54 @@
#include <sstream>
#include <typeinfo>
#include <boost/utility.hpp>
#include <boost/type_traits/is_enum.hpp>
#if PROPS_STANDALONE
#else
#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
#if PROPS_STANDALONE
// taken from: boost/utility/enable_if.hpp
#ifndef SG_LOG
# define SG_GENERAL 0
# define SG_ALERT 0
# define SG_WARN 1
# define SG_LOG(type, level, message) (type) ? (std::cerr <<message << endl) : (std::cout <<message << endl)
#endif
namespace boost {
template <bool B, class T = void>
struct enable_if_c {
typedef T type;
};
template <class T>
struct enable_if_c<false, T> {};
#include <simgear/math/SGMathFwd.hxx>
#include <simgear/math/sg_types.hxx>
template <class Cond, class T = void>
struct enable_if : public enable_if_c<Cond::value, T> {};
template <bool B, class T = void>
struct disable_if_c {
typedef T type;
};
template <class T>
struct disable_if_c<true, T> {};
template <class Cond, class T = void>
struct disable_if : public disable_if_c<Cond::value, T> {};
}
#else
# include <boost/utility.hpp>
# include <boost/type_traits/is_enum.hpp>
# include <simgear/debug/logstream.hxx>
# include <simgear/math/SGMathFwd.hxx>
# include <simgear/math/sg_types.hxx>
#endif
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
// XXX This whole file should be in the simgear namespace, but I don't
// have the guts yet...
using namespace std;
namespace simgear
{
@@ -1275,6 +1305,7 @@ public:
return ret;
}
#if !PROPS_STANDALONE
/**
* Interpolate current value to target value within given time.
*
@@ -1310,6 +1341,7 @@ public:
* Get the interpolation manager
*/
static simgear::PropertyInterpolationMgr* getInterpolationMgr();
#endif
/**
* Print the value of the property to a stream.
@@ -1807,7 +1839,11 @@ private:
// Convenience functions for use in templates
template<typename T>
#if PROPS_STANDALONE
T
#else
typename boost::disable_if<boost::is_enum<T>, T>::type
#endif
getValue(const SGPropertyNode*);
template<>
@@ -1871,7 +1907,11 @@ namespace simgear
/** Extract enum from SGPropertyNode */
template<typename T>
#if PROPS_STANDALONE
inline T
#else
inline typename boost::enable_if<boost::is_enum<T>, T>::type
#endif
getValue(const SGPropertyNode* node)
{
typedef simgear::enum_traits<T> Traits;

View File

@@ -201,7 +201,7 @@ SGMaterialCache *SGMaterialLib::generateMatCache(SGGeod center)
// Destructor
SGMaterialLib::~SGMaterialLib ( void ) {
SG_LOG( SG_GENERAL, SG_INFO, "SGMaterialLib::~SGMaterialLib() size=" << matlib.size());
SG_LOG( SG_TERRAIN, SG_DEBUG, "SGMaterialLib::~SGMaterialLib() size=" << matlib.size());
}
const SGMaterial *SGMaterialLib::findMaterial(const osg::Geode* geode)
@@ -244,5 +244,5 @@ SGMaterial *SGMaterialCache::find(const string& material) const
// Destructor
SGMaterialCache::~SGMaterialCache ( void ) {
SG_LOG( SG_GENERAL, SG_INFO, "SGMaterialCache::~SGMaterialCache() size=" << cache.size());
SG_LOG( SG_TERRAIN, SG_DEBUG, "SGMaterialCache::~SGMaterialCache() size=" << cache.size());
}

View File

@@ -364,6 +364,8 @@ public:
if (_textureProp) {
std::string textureName = _textureProp->getStringValue();
if (_textureName != textureName) {
_textureName = textureName;
while (stateSet->getTextureAttribute(0,
osg::StateAttribute::TEXTURE)) {
stateSet->removeTextureAttribute(0, osg::StateAttribute::TEXTURE);
@@ -377,8 +379,12 @@ public:
osg::StateAttribute::OVERRIDE);
stateSet->setTextureMode(0, GL_TEXTURE_2D,
osg::StateAttribute::ON);
_textureName = textureName;
}
} else {
SG_LOG(SG_IO, SG_WARN, "texture animation: requested texture : " << textureName << " not found. Searched paths:" );
for( osgDB::FilePathList::iterator it = _texturePathList.begin(); it != _texturePathList.end(); ++it ) {
SG_LOG(SG_IO, SG_WARN, " - " << *it );
}
}
}
}

View File

@@ -54,6 +54,7 @@ SGModelLib::panel_func SGModelLib::static_panelFunc = NULL;
void SGModelLib::init(const string &root_dir, SGPropertyNode* root)
{
osgDB::Registry::instance()->getDataFilePathList().push_front(root_dir);
osgDB::Registry::instance()->getOptions()->getDatabasePathList().push_front(root_dir);
static_propRoot = root;
}
@@ -114,6 +115,7 @@ SGModelLib::loadModel(const string &path,
{
osg::ref_ptr<SGReaderWriterOptions> opt;
opt = SGReaderWriterOptions::copyOrCreate(osgDB::Registry::instance()->getOptions());
opt->getDatabasePathList().push_front( osgDB::getFilePath(path) );
opt->setPropertyNode(prop_root ? prop_root: static_propRoot.get());
opt->setModelData(data);
@@ -136,8 +138,10 @@ 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) );
opt->setPropertyNode(prop_root ? prop_root: static_propRoot.get());
opt->setModelData(data);
opt->setLoadPanel(static_panelFunc);

View File

@@ -216,6 +216,46 @@ SGSun::build( SGPath path, double sun_size, SGPropertyNode *property_tree_Node )
sun_transform->addChild( geode );
// set up the brilliance state
geode = new osg::Geode;
stateSet = geode->getOrCreateStateSet();
stateSet->setRenderBinDetails(-9, "RenderBin");
texture = SGLoadTexture2D("brilliance.png", options.get());
stateSet->setTextureAttributeAndModes(0, texture);
// Build ssg structure
brilliance_cl = new osg::Vec4Array;
brilliance_cl->push_back(osg::Vec4(1, 1, 1, 1));
double brilliance_size = sun_size * 12.0;
osg::Vec3Array* brilliance_vl = new osg::Vec3Array;
brilliance_vl->push_back(osg::Vec3(-brilliance_size, 0, -brilliance_size));
brilliance_vl->push_back(osg::Vec3(brilliance_size, 0, -brilliance_size));
brilliance_vl->push_back(osg::Vec3(-brilliance_size, 0, brilliance_size));
brilliance_vl->push_back(osg::Vec3(brilliance_size, 0, brilliance_size));
osg::Vec2Array* brilliance_tl = new osg::Vec2Array;
brilliance_tl->push_back(osg::Vec2(0, 0));
brilliance_tl->push_back(osg::Vec2(1, 0));
brilliance_tl->push_back(osg::Vec2(0, 1));
brilliance_tl->push_back(osg::Vec2(1, 1));
geometry = new osg::Geometry;
geometry->setUseDisplayList(false);
geometry->setVertexArray(brilliance_vl);
geometry->setColorArray(brilliance_cl.get(), osg::Array::BIND_OVERALL);
geometry->setNormalBinding(osg::Geometry::BIND_OFF);
geometry->setTexCoordArray(0, brilliance_tl, osg::Array::BIND_PER_VERTEX);
geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 4));
geode->addDrawable(geometry);
sun_transform->addChild( geode );
// force a repaint of the sun colors with arbitrary defaults
repaint( 0.0, 1.0 );
@@ -262,7 +302,7 @@ bool SGSun::repaint( double sun_angle, double new_visibility ) {
}
// ok, now let's go and generate the sun and scene color
osg::Vec4 i_halo_color, o_halo_color, scene_color, sun_color;
osg::Vec4 i_halo_color, o_halo_color, scene_color, sun_color, brilliance_color;
// Some comments:
// * When the sunangle changes, light has to travel a longer
@@ -336,16 +376,29 @@ bool SGSun::repaint( double sun_angle, double new_visibility ) {
if (o_halo_color[3] > 1) o_halo_color[3] = 1;
if (o_halo_color[3] < 0) o_halo_color[3] = 0;
brilliance_color[0] = i_halo_color[0];
brilliance_color[1] = i_halo_color[1];
brilliance_color[2] = i_halo_color[2];
double norm = (i_halo_color[0] * i_halo_color[0] + i_halo_color[1] * i_halo_color[1] + i_halo_color[2] * i_halo_color[2])/1.732;
brilliance_color[3] = pow(norm, 6.0);
if (brilliance_color[3] < 0.0) {brilliance_color[3] = 0.0;}
gamma_correct_rgb( i_halo_color._v );
gamma_correct_rgb( o_halo_color._v );
gamma_correct_rgb( scene_color._v );
gamma_correct_rgb( sun_color._v );
gamma_correct_rgb( brilliance_color._v );
if (sun_angle >91.0 * 3.1415/180.0 + horizon_angle)
{
sun_color[3] = 0;
o_halo_color[3]=0;
i_halo_color[3]=0;
brilliance_color[3]=0;
}
(*sun_cl)[0] = sun_color;
@@ -356,6 +409,8 @@ bool SGSun::repaint( double sun_angle, double new_visibility ) {
ihalo_cl->dirty();
(*ohalo_cl)[0] = o_halo_color;
ohalo_cl->dirty();
(*brilliance_cl)[0] = brilliance_color;
brilliance_cl->dirty();
}
return true;
@@ -372,19 +427,14 @@ bool SGSun::reposition( double rightAscension, double declination,
{
// GST - GMT sidereal time
osg::Matrix T2, RA, DEC;
// xglRotatef( ((SGD_RADIANS_TO_DEGREES * rightAscension)- 90.0),
// 0.0, 0.0, 1.0);
RA.makeRotate(rightAscension - 90*SGD_DEGREES_TO_RADIANS, osg::Vec3(0, 0, 1));
// xglRotatef((SGD_RADIANS_TO_DEGREES * declination), 1.0, 0.0, 0.0);
DEC.makeRotate(declination, osg::Vec3(1, 0, 0));
// xglTranslatef(0,sun_dist);
T2.makeTranslate(osg::Vec3(0, sun_dist, 0));
sun_transform->setMatrix(T2*DEC*RA);
// Suncolor related things:
if ( prev_sun_angle != sun_angle ) {
if ( sun_angle == 0 ) sun_angle = 0.1;
@@ -412,7 +462,7 @@ bool SGSun::reposition( double rightAscension, double declination,
if ( alt_half < 0.0 ) alt_half = 0.0;
//angle at which the sun is visible below the horizon
horizon_angle = acos(r_earth/position_radius);
horizon_angle = acos(min(r_earth/position_radius, 1.0));
// Push the data to the property tree, so it can be used in the enviromental code
if ( env_node ){

View File

@@ -45,6 +45,7 @@ class SGSun : public SGReferenced {
osg::ref_ptr<osg::Vec4Array> scene_cl;
osg::ref_ptr<osg::Vec4Array> ihalo_cl;
osg::ref_ptr<osg::Vec4Array> ohalo_cl;
osg::ref_ptr<osg::Vec4Array> brilliance_cl;
double visibility;
double prev_sun_angle;

View File

@@ -44,6 +44,7 @@
#include <simgear/misc/sgstream.hxx>
#include <simgear/scene/util/OptionsReadFileCallback.hxx>
#include <simgear/scene/util/OsgMath.hxx>
#include <simgear/scene/util/QuadTreeBuilder.hxx>
#include <simgear/scene/util/RenderConstants.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/scene/tgdb/apt_signs.hxx>
@@ -113,48 +114,79 @@ struct ReaderWriterSTG::_ModelBin {
};
class DelayLoadReadFileCallback : public OptionsReadFileCallback {
private:
// QuadTreeBuilder for structuring static objects
struct MakeQuadLeaf {
osg::LOD* operator() () const { return new osg::LOD; }
};
struct AddModelLOD {
void operator() (osg::LOD* leaf, _ObjectStatic o) const
{
osg::ref_ptr<osg::Node> node;
if (o._proxy) {
osg::ref_ptr<osg::ProxyNode> proxy = new osg::ProxyNode;
proxy->setName("proxyNode");
proxy->setLoadingExternalReferenceMode(osg::ProxyNode::DEFER_LOADING_TO_DATABASE_PAGER);
proxy->setFileName(0, o._name);
proxy->setDatabaseOptions(o._options.get());
// Give the node some values so the Quadtree builder has
// a BoundingBox to work with prior to the model being loaded.
proxy->setCenter(osg::Vec3f(0.0f,0.0f,0.0f));
proxy->setRadius(10);
proxy->setCenterMode(osg::ProxyNode::UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED);
node = proxy;
} else {
node = osgDB::readRefNodeFile(o._name, o._options.get());
if (!node.valid()) {
SG_LOG(SG_TERRAIN, SG_ALERT, o._errorLocation << ": Failed to load "
<< o._token << " '" << o._name << "'");
return;
}
}
if (SGPath(o._name).lower_extension() == "ac")
node->setNodeMask(~simgear::MODELLIGHT_BIT);
osg::Matrix matrix;
matrix = makeZUpFrame(SGGeod::fromDegM(o._lon, o._lat, o._elev));
matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(o._hdg), osg::Vec3(0, 0, 1)));
matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(o._pitch), osg::Vec3(0, 1, 0)));
matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(o._roll), osg::Vec3(1, 0, 0)));
osg::MatrixTransform* matrixTransform;
matrixTransform = new osg::MatrixTransform(matrix);
matrixTransform->setName("rotateStaticObject");
matrixTransform->setDataVariance(osg::Object::STATIC);
matrixTransform->addChild(node.get());
leaf->addChild(matrixTransform, 0, 20000); //TODO: Make configurable?
}
};
struct GetModelLODCoord {
GetModelLODCoord() {}
GetModelLODCoord(const GetModelLODCoord& rhs)
{}
osg::Vec3 operator() (const _ObjectStatic& o) const
{
SGVec3d coord;
SGGeodesy::SGGeodToCart(SGGeod::fromDegM(o._lon, o._lat, o._elev), coord);
return toOsg(coord);
}
};
typedef QuadTreeBuilder<osg::LOD*, _ObjectStatic, MakeQuadLeaf, AddModelLOD,
GetModelLODCoord> STGObjectsQuadtree;
public:
virtual osgDB::ReaderWriter::ReadResult
readNode(const std::string&, const osgDB::Options*)
{
osg::ref_ptr<osg::Group> group = new osg::Group;
STGObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD()));
quadtree.buildQuadTree(_objectStaticList.begin(), _objectStaticList.end());
osg::ref_ptr<osg::Group> group = quadtree.getRoot();
group->setName("STG-group-A");
group->setDataVariance(osg::Object::STATIC);
for (std::list<_ObjectStatic>::iterator i = _objectStaticList.begin(); i != _objectStaticList.end(); ++i) {
osg::ref_ptr<osg::Node> node;
if (i->_proxy) {
osg::ref_ptr<osg::ProxyNode> proxy = new osg::ProxyNode;
proxy->setName("proxyNode");
proxy->setLoadingExternalReferenceMode(osg::ProxyNode::DEFER_LOADING_TO_DATABASE_PAGER);
proxy->setFileName(0, i->_name);
proxy->setDatabaseOptions(i->_options.get());
node = proxy;
} else {
node = osgDB::readRefNodeFile(i->_name, i->_options.get());
if (!node.valid()) {
SG_LOG(SG_TERRAIN, SG_ALERT, i->_errorLocation << ": Failed to load "
<< i->_token << " '" << i->_name << "'");
continue;
}
}
if (SGPath(i->_name).lower_extension() == "ac")
node->setNodeMask(~simgear::MODELLIGHT_BIT);
osg::Matrix matrix;
matrix = makeZUpFrame(SGGeod::fromDegM(i->_lon, i->_lat, i->_elev));
matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_hdg), osg::Vec3(0, 0, 1)));
matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_pitch), osg::Vec3(0, 1, 0)));
matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_roll), osg::Vec3(1, 0, 0)));
osg::MatrixTransform* matrixTransform;
matrixTransform = new osg::MatrixTransform(matrix);
matrixTransform->setName("positionStaticObject");
matrixTransform->setDataVariance(osg::Object::STATIC);
matrixTransform->addChild(node.get());
group->addChild(matrixTransform);
}
simgear::AirportSignBuilder signBuilder(_options->getMaterialLib(), _bucket.get_center());
for (std::list<_Sign>::iterator i = _signList.begin(); i != _signList.end(); ++i)
signBuilder.addSign(SGGeod::fromDegM(i->_lon, i->_lat, i->_elev), i->_hdg, i->_name, i->_size);
@@ -266,7 +298,7 @@ struct ReaderWriterSTG::_ModelBin {
// read a line
std::string line;
std::getline(stream, line);
// strip comments
std::string::size_type hash_pos = line.find('#');
if (hash_pos != std::string::npos)

View File

@@ -97,7 +97,7 @@ public:
virtual ~SGTileDetailsCallback()
{
num_tdcb--;
SG_LOG( SG_GENERAL, SG_INFO, "SGTileDetailsCallback::~SGTileDetailsCallback() num cbs left " << num_tdcb );
SG_LOG( SG_TERRAIN, SG_DEBUG, "SGTileDetailsCallback::~SGTileDetailsCallback() num cbs left " << num_tdcb );
}
virtual osgDB::ReaderWriter::ReadResult readNode(
@@ -736,9 +736,9 @@ public:
if (!found) {
bin = new TreeBin();
bin->texture = mat->get_tree_texture();
SG_LOG(SG_INPUT, SG_DEBUG, "Tree texture " << bin->texture);
SG_LOG(SG_TERRAIN, SG_DEBUG, "Tree texture " << bin->texture);
bin->teffect = mat->get_tree_effect();
SG_LOG(SG_INPUT, SG_DEBUG, "Tree effect " << bin->teffect);
SG_LOG(SG_TERRAIN, SG_DEBUG, "Tree effect " << bin->teffect);
bin->range = mat->get_tree_range();
bin->width = mat->get_tree_width();
bin->height = mat->get_tree_height();
@@ -789,11 +789,6 @@ public:
float coverage = mat->get_light_coverage();
if (coverage <= 0)
continue;
if (coverage < 10000.0) {
SG_LOG(SG_INPUT, SG_ALERT, "Light coverage is "
<< coverage << ", pushing up to 10000");
coverage = 10000;
}
int texIndex = matTris[i].getTextureIndex();

View File

@@ -51,6 +51,7 @@
#include <map>
#include <simgear/compiler.h>
#include <simgear/version.h>
#include "terrasync.hxx"
@@ -228,7 +229,7 @@ protected:
virtual void onFail()
{
SG_LOG(SG_TERRAIN, SG_ALERT, "Failed to query TerraSync SVN server");
SG_LOG(SG_TERRASYNC, SG_ALERT, "Failed to query TerraSync SVN server");
HTTP::Request::onFail();
}
@@ -343,7 +344,7 @@ SGTerraSync::SvnThread::SvnThread() :
_stop(false),
_use_svn(true)
{
_http.setUserAgent("terrascenery-" SG_STRINGIZE(SG_VERSION));
_http.setUserAgent("terrascenery-" SG_STRINGIZE(SIMGEAR_VERSION));
}
void SGTerraSync::SvnThread::stop()
@@ -369,7 +370,7 @@ bool SGTerraSync::SvnThread::start()
if (_local_dir=="")
{
SG_LOG(SG_TERRAIN,SG_ALERT,
SG_LOG(SG_TERRASYNC,SG_ALERT,
"Cannot start scenery download. Local cache directory is undefined.");
_fail_count++;
_stalled = true;
@@ -379,7 +380,7 @@ bool SGTerraSync::SvnThread::start()
SGPath path(_local_dir);
if (!path.exists())
{
SG_LOG(SG_TERRAIN,SG_ALERT,
SG_LOG(SG_TERRASYNC,SG_ALERT,
"Cannot start scenery download. Directory '" << _local_dir <<
"' does not exist. Set correct directory path or create directory folder.");
_fail_count++;
@@ -390,7 +391,7 @@ bool SGTerraSync::SvnThread::start()
path.append("version");
if (path.exists())
{
SG_LOG(SG_TERRAIN,SG_ALERT,
SG_LOG(SG_TERRASYNC,SG_ALERT,
"Cannot start scenery download. Directory '" << _local_dir <<
"' contains the base package. Use a separate directory.");
_fail_count++;
@@ -403,7 +404,7 @@ bool SGTerraSync::SvnThread::start()
if ((!_use_svn)&&(_rsync_server==""))
{
SG_LOG(SG_TERRAIN,SG_ALERT,
SG_LOG(SG_TERRASYNC,SG_ALERT,
"Cannot start scenery download. Rsync scenery server is undefined.");
_fail_count++;
_stalled = true;
@@ -435,7 +436,7 @@ bool SGTerraSync::SvnThread::start()
// not really an alert - but we want to (always) see this message, so user is
// aware we're downloading scenery (and using bandwidth).
SG_LOG(SG_TERRAIN,SG_ALERT,
SG_LOG(SG_TERRASYNC,SG_ALERT,
"Starting automatic scenery download/synchronization. "
<< status
<< "Directory: '" << _local_dir << "'.");
@@ -475,7 +476,7 @@ bool SGTerraSync::SvnThread::runExternalSyncCommand(const char* dir)
#else
command = buf.str();
#endif
SG_LOG(SG_TERRAIN,SG_DEBUG, "sync command '" << command << "'");
SG_LOG(SG_TERRASYNC,SG_DEBUG, "sync command '" << command << "'");
#ifdef SG_WINDOWS
// tbd: does Windows support "popen"?
@@ -490,7 +491,7 @@ bool SGTerraSync::SvnThread::runExternalSyncCommand(const char* dir)
if (rc)
{
SG_LOG(SG_TERRAIN,SG_ALERT,
SG_LOG(SG_TERRASYNC,SG_ALERT,
"Failed to synchronize directory '" << dir << "', " <<
"error code= " << rc);
return false;
@@ -505,7 +506,7 @@ void SGTerraSync::SvnThread::run()
{
if (_svn_server.empty()) {
SG_LOG(SG_TERRAIN,SG_INFO, "Querying closest TerraSync server");
SG_LOG(SG_TERRASYNC,SG_INFO, "Querying closest TerraSync server");
ServerSelectQuery* ssq = new ServerSelectQuery;
HTTP::Request_ptr req = ssq;
_http.makeRequest(req);
@@ -515,12 +516,12 @@ void SGTerraSync::SvnThread::run()
if (req->readyState() == HTTP::Request::DONE) {
_svn_server = ssq->svnUrl();
SG_LOG(SG_TERRAIN,SG_INFO, "Closest TerraSync server:" << _svn_server);
SG_LOG(SG_TERRASYNC,SG_INFO, "Closest TerraSync server:" << _svn_server);
} else {
SG_LOG(SG_TERRAIN,SG_WARN, "Failed to query closest TerraSync server");
SG_LOG(SG_TERRASYNC,SG_WARN, "Failed to query closest TerraSync server");
}
} else {
SG_LOG(SG_TERRAIN,SG_INFO, "Explicit: TerraSync server:" << _svn_server);
SG_LOG(SG_TERRASYNC,SG_INFO, "Explicit: TerraSync server:" << _svn_server);
}
if (_svn_server.empty()) {
@@ -551,7 +552,7 @@ void SGTerraSync::SvnThread::runExternal()
SyncItem::Status cacheStatus = isPathCached(next);
if (cacheStatus != SyncItem::Invalid) {
_cache_hits++;
SG_LOG(SG_TERRAIN, SG_DEBUG,
SG_LOG(SG_TERRASYNC, SG_DEBUG,
"Cache hit for: '" << next._dir << "'");
next._status = cacheStatus;
_freshTiles.push_back(next);
@@ -581,7 +582,7 @@ void SGTerraSync::SvnThread::syncPathExternal(const SyncItem& next)
if (isNewDirectory) {
int rc = path.create_dir( 0755 );
if (rc) {
SG_LOG(SG_TERRAIN,SG_ALERT,
SG_LOG(SG_TERRASYNC,SG_ALERT,
"Cannot create directory '" << path << "', return code = " << rc );
throw sg_exception("Cannot create directory for terrasync", path.str());
}
@@ -605,9 +606,9 @@ void SGTerraSync::SvnThread::updateSyncSlot(SyncSlot &slot)
if (slot.repository.get()) {
if (slot.repository->isDoingSync()) {
#if 1
if (slot.stamp.elapsedMSec() > slot.nextWarnTimeout) {
SG_LOG(SG_TERRAIN, SG_INFO, "sync taking a long time:" << slot.currentItem._dir << " taken " << slot.stamp.elapsedMSec());
SG_LOG(SG_TERRAIN, SG_INFO, "HTTP status:" << _http.hasActiveRequests());
if (slot.stamp.elapsedMSec() > (int)slot.nextWarnTimeout) {
SG_LOG(SG_TERRASYNC, SG_INFO, "sync taking a long time:" << slot.currentItem._dir << " taken " << slot.stamp.elapsedMSec());
SG_LOG(SG_TERRASYNC, SG_INFO, "HTTP request count:" << _http.hasActiveRequests());
slot.nextWarnTimeout += 10000;
}
#endif
@@ -622,7 +623,7 @@ void SGTerraSync::SvnThread::updateSyncSlot(SyncSlot &slot)
fail(slot.currentItem);
} else {
updated(slot.currentItem, slot.isNewDirectory);
SG_LOG(SG_TERRAIN, SG_DEBUG, "sync of " << slot.repository->baseUrl() << " finished ("
SG_LOG(SG_TERRASYNC, SG_DEBUG, "sync of " << slot.repository->baseUrl() << " finished ("
<< slot.stamp.elapsedMSec() << " msec");
}
@@ -642,7 +643,7 @@ void SGTerraSync::SvnThread::updateSyncSlot(SyncSlot &slot)
if (slot.isNewDirectory) {
int rc = path.create_dir( 0755 );
if (rc) {
SG_LOG(SG_TERRAIN,SG_ALERT,
SG_LOG(SG_TERRASYNC,SG_ALERT,
"Cannot create directory '" << path << "', return code = " << rc );
fail(slot.currentItem);
return;
@@ -661,7 +662,7 @@ void SGTerraSync::SvnThread::updateSyncSlot(SyncSlot &slot)
slot.nextWarnTimeout = 20000;
slot.stamp.stamp();
slot.busy = true;
SG_LOG(SG_TERRAIN, SG_INFO, "sync of " << slot.repository->baseUrl() << " started, queue size is " << slot.queue.size());
SG_LOG(SG_TERRASYNC, SG_INFO, "sync of " << slot.repository->baseUrl() << " started, queue size is " << slot.queue.size());
}
}
@@ -682,7 +683,7 @@ void SGTerraSync::SvnThread::runInternal()
SyncItem::Status cacheStatus = isPathCached(next);
if (cacheStatus != SyncItem::Invalid) {
_cache_hits++;
SG_LOG(SG_TERRAIN, SG_DEBUG, "\nTerraSync Cache hit for: '" << next._dir << "'");
SG_LOG(SG_TERRASYNC, SG_DEBUG, "\nTerraSync Cache hit for: '" << next._dir << "'");
next._status = cacheStatus;
_freshTiles.push_back(next);
_is_dirty = true;
@@ -739,8 +740,8 @@ void SGTerraSync::SvnThread::fail(SyncItem failedItem)
_fail_count++;
failedItem._status = SyncItem::Failed;
_freshTiles.push_back(failedItem);
SG_LOG(SG_TERRAIN,SG_INFO,
"Faield to sync'" << failedItem._dir << "'");
SG_LOG(SG_TERRASYNC,SG_INFO,
"Failed to sync'" << failedItem._dir << "'");
_completedTiles[ failedItem._dir ] = now + UpdateInterval::FailedAttempt;
_is_dirty = true;
}
@@ -765,7 +766,7 @@ void SGTerraSync::SvnThread::updated(SyncItem item, bool isNewDirectory)
time_t now = time(0);
_consecutive_errors = 0;
_success_count++;
SG_LOG(SG_TERRAIN,SG_INFO,
SG_LOG(SG_TERRASYNC,SG_INFO,
"Successfully synchronized directory '" << item._dir << "'");
item._status = SyncItem::Updated;
@@ -791,7 +792,7 @@ void SGTerraSync::SvnThread::initCompletedTilesPersistentCache()
try {
readProperties(_persistentCachePath.str(), cacheRoot);
} catch (sg_exception& e) {
SG_LOG(SG_TERRAIN, SG_INFO, "corrupted persistent cache, discarding");
SG_LOG(SG_TERRASYNC, SG_INFO, "corrupted persistent cache, discarding");
return;
}
@@ -852,7 +853,7 @@ SGTerraSync::SGTerraSync() :
_inited(false)
{
_svnThread = new SvnThread();
_log = new BufferedLogCallback(SG_TERRAIN, SG_INFO);
_log = new BufferedLogCallback(SG_TERRASYNC, SG_INFO);
_log->truncateAt(255);
sglog().addCallback(_log);
@@ -977,13 +978,13 @@ void SGTerraSync::update(double)
{
if (_svnThread->_stalled)
{
SG_LOG(SG_TERRAIN,SG_ALERT,
SG_LOG(SG_TERRASYNC,SG_ALERT,
"Automatic scenery download/synchronization stalled. Too many errors.");
}
else
{
// not really an alert - just always show this message
SG_LOG(SG_TERRAIN,SG_ALERT,
SG_LOG(SG_TERRASYNC,SG_ALERT,
"Automatic scenery download/synchronization has stopped.");
}
_stalledNode->setBoolValue(_svnThread->_stalled);
@@ -1085,4 +1086,4 @@ bool SGTerraSync::isDataDirPending(const std::string& dataDir) const
void SGTerraSync::reposition()
{
// stub, remove
}
}

View File

@@ -18,3 +18,4 @@
#cmakedefine SYSTEM_EXPAT
#cmakedefine ENABLE_SOUND
#cmakedefine ENABLE_CURL

View File

@@ -28,6 +28,7 @@
#include <stdlib.h> // rand(), free()
#include <cstring>
#include <stdio.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/exception.hxx>
@@ -78,8 +79,12 @@ SGSoundSample::SGSoundSample() :
_playing(false),
_static_changed(true),
_out_of_range(false),
_is_file(false)
_is_file(false),
_use_pos_props(false)
{
_pos_prop[0] = 0;
_pos_prop[1] = 0;
_pos_prop[2] = 0;
}
// constructor
@@ -114,10 +119,14 @@ SGSoundSample::SGSoundSample(const char *file, const SGPath& currentDir) :
_playing(false),
_static_changed(true),
_out_of_range(false),
_is_file(true)
_is_file(true),
_use_pos_props(false)
{
SGPath p = simgear::ResourceManager::instance()->findPath(file, currentDir);
_refname = p.str();
_pos_prop[0] = 0;
_pos_prop[1] = 0;
_pos_prop[2] = 0;
}
// constructor
@@ -152,10 +161,14 @@ SGSoundSample::SGSoundSample( const unsigned char** data,
_playing(false),
_static_changed(true),
_out_of_range(false),
_is_file(false)
_is_file(false),
_use_pos_props(false)
{
SG_LOG( SG_SOUND, SG_DEBUG, "In memory sounds sample" );
_data = (unsigned char*)*data; *data = NULL;
_pos_prop[0] = 0;
_pos_prop[1] = 0;
_pos_prop[2] = 0;
}
// constructor
@@ -189,10 +202,14 @@ SGSoundSample::SGSoundSample( void** data, int len, int freq, int format ) :
_playing(false),
_static_changed(true),
_out_of_range(false),
_is_file(false)
_is_file(false),
_use_pos_props(false)
{
SG_LOG( SG_SOUND, SG_DEBUG, "In memory sounds sample" );
_data = (unsigned char*)*data; *data = NULL;
_pos_prop[0] = 0;
_pos_prop[1] = 0;
_pos_prop[2] = 0;
}
@@ -203,9 +220,16 @@ SGSoundSample::~SGSoundSample() {
void SGSoundSample::update_pos_and_orientation() {
_absolute_pos = _base_pos;
if (_relative_pos[0] || _relative_pos[1] || _relative_pos[2] ) {
_absolute_pos += _rotation.rotate( _relative_pos );
if (_use_pos_props) {
if (_pos_prop[0]) _absolute_pos[0] = _pos_prop[0]->getDoubleValue();
if (_pos_prop[1]) _absolute_pos[1] = _pos_prop[1]->getDoubleValue();
if (_pos_prop[2]) _absolute_pos[2] = _pos_prop[2]->getDoubleValue();
}
else {
_absolute_pos = _base_pos;
if (_relative_pos[0] || _relative_pos[1] || _relative_pos[2] ) {
_absolute_pos += _rotation.rotate( _relative_pos );
}
}
_orivec = SGVec3f::zeros();

View File

@@ -30,6 +30,7 @@
#include <simgear/structure/SGReferenced.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/math/SGMath.hxx>
#include <simgear/props/props.hxx>
class SGPath;
@@ -334,7 +335,13 @@ public:
* @param pos position in Cartesian coordinates
*/
inline void set_position( const SGVec3d& pos ) {
_base_pos = pos; _changed = true;
_base_pos = pos; _changed = true;
}
inline void set_position_properties(SGPropertyNode_ptr pos[3]) {
_pos_prop[0] = pos[0]; _pos_prop[1] = pos[1]; _pos_prop[2] = pos[2];
if (pos[0] || pos[1] || pos[2]) _use_pos_props = true;
_changed = true;
}
/**
@@ -458,6 +465,7 @@ public:
* @return Sample name
*/
inline std::string get_sample_name() const { return _refname; }
inline void set_sample_name(const std::string& refname) { _refname = refname; }
inline virtual bool is_queue() const { return false; }
@@ -476,6 +484,7 @@ protected:
private:
// Position of the source sound.
SGPropertyNode_ptr _pos_prop[3]; // always absolute
SGVec3d _absolute_pos; // absolute position
SGVec3d _relative_pos; // position relative to the base position
SGVec3d _direction; // orientation offset
@@ -513,6 +522,7 @@ private:
bool _static_changed;
bool _out_of_range;
bool _is_file;
bool _use_pos_props;
std::string random_string();
};

View File

@@ -239,7 +239,6 @@ void SGSoundMgr::init()
if (_vendor == "Creative Labs Inc.") {
_bad_doppler = true;
} else if (_vendor == "OpenAL Community" && _renderer == "OpenAL Soft") {
_bad_doppler = true;
}

View File

@@ -34,7 +34,7 @@
#include <vector>
#include <map>
#include <memory> // for std::auto_ptr
#include <simgear/compiler.h>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/math/SGMath.hxx>
@@ -55,7 +55,7 @@ public:
void init();
void update(double dt);
void suspend();
void resume();
void stop();
@@ -93,7 +93,7 @@ public:
*/
bool add( SGSampleGroup *sgrp, const std::string& refname );
/**
/**
* Remove a sample group from the sound manager.
* @param refname Reference name of the sample group to remove
* @return true if successful, false otherwise
@@ -268,11 +268,12 @@ public:
const std::string& get_vendor() { return _vendor; }
const std::string& get_renderer() { return _renderer; }
static const char* subsystemName() { return "sound"; };
private:
class SoundManagerPrivate;
/// private implementation object
std::auto_ptr<SoundManagerPrivate> d;
bool _active;
bool _changed;
float _volume;
@@ -298,5 +299,3 @@ private:
#endif // _SG_SOUNDMGR_OPENAL_HXX

View File

@@ -31,6 +31,7 @@
#include <simgear/compiler.h>
#include <string.h>
#include <stdio.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/props/props.hxx>
@@ -249,10 +250,27 @@ SGXmlSound::init( SGPropertyNode *root,
//
SGVec3f offset_pos = SGVec3f::zeros();
SGPropertyNode_ptr prop = node->getChild("position");
SGPropertyNode_ptr pos_prop[3];
if ( prop != NULL ) {
offset_pos[0] = -prop->getDoubleValue("x", 0.0);
offset_pos[1] = -prop->getDoubleValue("y", 0.0);
offset_pos[2] = -prop->getDoubleValue("z", 0.0);
pos_prop[0] = prop->getChild("x");
if (pos_prop[0]) pos_prop[0] = pos_prop[0]->getNode("property");
if (pos_prop[0]) {
pos_prop[0] = root->getNode(pos_prop[0]->getStringValue(), true);
}
pos_prop[1] = prop->getChild("y");
if (pos_prop[1]) pos_prop[1] = pos_prop[1]->getNode("property");
if (pos_prop[1]) {
pos_prop[1] = root->getNode(pos_prop[1]->getStringValue(), true);
}
pos_prop[2] = prop->getChild("z");
if (pos_prop[2]) pos_prop[2] = pos_prop[1]->getNode("property");
if (pos_prop[2]) {
pos_prop[2] = root->getNode(pos_prop[2]->getStringValue(), true);
}
}
//
@@ -284,9 +302,11 @@ SGXmlSound::init( SGPropertyNode *root,
_sample = new SGSoundSample(soundFileStr.c_str(), path);
if (!_sample->file_path().exists()) {
throw sg_io_exception("XML sound: couldn't find file: '" + soundFileStr + "'");
return;
}
_sample->set_relative_position( offset_pos );
_sample->set_position_properties( pos_prop );
_sample->set_direction( dir );
_sample->set_audio_cone( inner, outer, outer_gain );
_sample->set_reference_dist( reference_dist );

View File

@@ -1,6 +1,6 @@
/* -*-c++-*-
*
* Copyright (C) 2005-2006 Mathias Froehlich
* Copyright (C) 2005-2006 Mathias Froehlich
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as

View File

@@ -234,6 +234,7 @@ SGSubsystemGroup::update (double delta_time_sec)
if ((delta_time_sec > 0.0) && (_fixedUpdateTime > 0.0)) {
double localDelta = delta_time_sec + _updateTimeRemainder;
loopCount = SGMiscd::roundToInt(localDelta / _fixedUpdateTime);
loopCount = std::max(0, loopCount);
_updateTimeRemainder = delta_time_sec - (loopCount * _fixedUpdateTime);
delta_time_sec = _fixedUpdateTime;
}
@@ -301,8 +302,6 @@ SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
double min_step_sec)
{
Member * member = get_member(name, true);
if (member->subsystem != 0)
delete member->subsystem;
member->name = name;
member->subsystem = subsystem;
member->min_step_sec = min_step_sec;
@@ -430,11 +429,11 @@ SGSubsystemGroup::Member::update (double delta_time_sec)
SGSubsystemMgr::SGSubsystemMgr () :
_groups(MAX_GROUPS),
_initPosition(0)
{
for (int i = 0; i < MAX_GROUPS; i++) {
_groups[i] = new SGSubsystemGroup;
}
for (int i = 0; i < MAX_GROUPS; i++)
_groups[i].reset(new SGSubsystemGroup);
}
SGSubsystemMgr::~SGSubsystemMgr ()
@@ -442,10 +441,7 @@ SGSubsystemMgr::~SGSubsystemMgr ()
// ensure get_subsystem returns NULL from now onwards,
// before the SGSubsystemGroup destructors are run
_subsystem_map.clear();
for (int i = 0; i < MAX_GROUPS; i++) {
delete _groups[i];
}
_groups.clear();
}
void

View File

@@ -39,7 +39,7 @@ private:
std::string eventName;
SGTimeStamp time;
public:
public:
TimingInfo(const std::string& name, const SGTimeStamp &t) :
eventName(name), time(t)
{ }
@@ -153,7 +153,7 @@ public:
INIT_DONE, ///< subsystem is fully initialised
INIT_CONTINUE ///< init should be called again
} InitStatus;
virtual InitStatus incrementalInit ();
/**
@@ -186,7 +186,7 @@ public:
* </p>
*/
virtual void shutdown ();
/**
* Acquire the subsystem's property bindings.
*
@@ -267,7 +267,7 @@ public:
void reportTiming(void);
/**
* Place time stamps at strategic points in the execution of subsystems
* Place time stamps at strategic points in the execution of subsystems
* update() member functions. Predominantly for debugging purposes.
*/
void stamp(const std::string& name);
@@ -324,12 +324,12 @@ public:
*
*/
void set_fixed_update_time(double fixed_dt);
/**
* retrive list of member subsystem names
*/
*/
string_list member_names() const;
private:
class Member;
@@ -337,14 +337,16 @@ private:
typedef std::vector<Member *> MemberVec;
MemberVec _members;
double _fixedUpdateTime;
double _updateTimeRemainder;
/// index of the member we are currently init-ing
unsigned int _initPosition;
};
typedef SGSharedPtr<SGSubsystemGroup> SGSubsystemGroupRef;
/**
* Manage subsystems for FlightGear.
*
@@ -396,7 +398,7 @@ public:
virtual void add (const char * name,
SGSubsystem * subsystem,
GroupType group = GENERAL,
GroupType group = GENERAL,
double min_time_sec = 0);
/**
@@ -412,10 +414,16 @@ public:
void reportTiming();
void setReportTimingCb(void* userData,SGSubsystemTimingCb cb) {reportTimingCb = cb;reportTimingUserData = userData;}
template<class T>
T* get_subsystem() const
{
return dynamic_cast<T*>(get_subsystem(T::subsystemName()));
}
private:
SGSubsystemGroup* _groups[MAX_GROUPS];
std::vector<SGSubsystemGroupRef> _groups;
unsigned int _initPosition;
// non-owning reference
typedef std::map<std::string, SGSubsystem*> SubsystemDict;
SubsystemDict _subsystem_map;

View File

@@ -170,13 +170,6 @@ static double sidereal_course( time_t cur_time, const struct tm *gmt, double lng
return lstTmp;
}
/** Deprecated method. To be removed after the next release... */
void SGTime::update( double lon_rad, double lat_rad, time_t ct, long int warp )
{
const SGGeod& location = SGGeod::fromRad(lon_rad, lat_rad);
update(location, ct, warp);
}
// Update the time related variables
void SGTime::update( const SGGeod& location, time_t ct, long int warp )
{

View File

@@ -151,9 +151,6 @@ public:
*/
void update( const SGGeod& location, time_t ct, long int warp );
/** Deprecated method. To be removed after the next release... */
void update( double lon_rad, double lat_rad, time_t ct, long int warp ) DEPRECATED;
/**
* Given lon/lat, update timezone information and local_offset
* The updateLocal() method is intended to be called less

View File

@@ -1 +1 @@
3.6.0
2016.2.0