Compare commits
56 Commits
version/3.
...
version/3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7a60d4dc4 | ||
|
|
a841fcc89e | ||
|
|
b91d1a3f6a | ||
|
|
1378511c13 | ||
|
|
9a9cd62957 | ||
|
|
a9742fba7c | ||
|
|
9ea772f938 | ||
|
|
e64902ae8c | ||
|
|
0b1399479a | ||
|
|
0369d1f506 | ||
|
|
f19cf6d56a | ||
|
|
d12d1b2c3a | ||
|
|
b7fbb79565 | ||
|
|
541239ceac | ||
|
|
fd74095939 | ||
|
|
b24d190e55 | ||
|
|
8b351520bd | ||
|
|
5bbdcfd240 | ||
|
|
51ff30f386 | ||
|
|
6683092bb2 | ||
|
|
2c6f9de020 | ||
|
|
686f095f1e | ||
|
|
089fc5ea0a | ||
|
|
72ae14227e | ||
|
|
0e9948f9d4 | ||
|
|
0b6738b616 | ||
|
|
3c204e84f4 | ||
|
|
7774b76ad2 | ||
|
|
acd655b37b | ||
|
|
1a09683351 | ||
|
|
181afb7fd0 | ||
|
|
9d1354f6bd | ||
|
|
596591bb64 | ||
|
|
a67a984d29 | ||
|
|
37a963da92 | ||
|
|
384a700e05 | ||
|
|
7d2ecef14a | ||
|
|
bc72c34d0f | ||
|
|
ca7acb1f2c | ||
|
|
1365a02aea | ||
|
|
611785c04b | ||
|
|
e5995208a9 | ||
|
|
6f15bb415f | ||
|
|
ce7f78e0ca | ||
|
|
6323477a35 | ||
|
|
8c38f799ad | ||
|
|
1bf0b7222d | ||
|
|
0cc5374fe7 | ||
|
|
b2ac9982d4 | ||
|
|
84cbfb2e98 | ||
|
|
7479cadbba | ||
|
|
f711306085 | ||
|
|
148640be34 | ||
|
|
27a91062bd | ||
|
|
dc1816bb08 | ||
|
|
e836e85697 |
@@ -1,9 +1,27 @@
|
||||
cmake_minimum_required (VERSION 2.6.4)
|
||||
|
||||
if(COMMAND cmake_policy)
|
||||
if(POLICY CMP0054)
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
endif()
|
||||
if(POLICY CMP0042)
|
||||
cmake_policy(SET CMP0042 NEW)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include (CheckFunctionExists)
|
||||
include (CheckIncludeFile)
|
||||
include (CheckLibraryExists)
|
||||
include (CheckCXXSourceCompiles)
|
||||
include (CheckCXXCompilerFlag)
|
||||
|
||||
# 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)
|
||||
|
||||
project(SimGear)
|
||||
|
||||
# read 'version' file into a variable (stripping any newlines or spaces)
|
||||
@@ -34,7 +52,7 @@ SET(CPACK_INSTALL_CMAKE_PROJECTS ${CMAKE_CURRENT_BINARY_DIR};SimGear;ALL;/)
|
||||
|
||||
# split version string into components, note CMAKE_MATCH_0 is the entire regexp match
|
||||
string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" CPACK_PACKAGE_VERSION ${SIMGEAR_VERSION} )
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3})
|
||||
|
||||
@@ -163,11 +181,16 @@ if(APPLE)
|
||||
find_library(COCOA_LIBRARY Cocoa)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR
|
||||
${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
find_package(Threads REQUIRED)
|
||||
endif()
|
||||
|
||||
# Somehow this only works if included before searching for Boost...
|
||||
include(BoostTestTargets)
|
||||
|
||||
find_package(Boost REQUIRED)
|
||||
set (BOOST_CXX_FLAGS "-DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION -DBOOST_BIMAP_DISABLE_SERIALIZATION")
|
||||
set (BOOST_CXX_FLAGS "-DBOOST_BIMAP_DISABLE_SERIALIZATION")
|
||||
|
||||
if(SIMGEAR_HEADLESS)
|
||||
message(STATUS "SimGear mode: HEADLESS")
|
||||
@@ -175,17 +198,16 @@ if(SIMGEAR_HEADLESS)
|
||||
else()
|
||||
message(STATUS "SimGear mode: NORMAL")
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
|
||||
if (ENABLE_SOUND)
|
||||
find_package(OpenAL REQUIRED)
|
||||
message(STATUS "Sound support: ENABLED")
|
||||
endif(ENABLE_SOUND)
|
||||
|
||||
|
||||
find_package(OpenSceneGraph 3.2.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgViewer osgUtil)
|
||||
endif(SIMGEAR_HEADLESS)
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if (SYSTEM_EXPAT)
|
||||
message(STATUS "Requested to use system Expat library, forcing SIMGEAR_SHARED to true")
|
||||
@@ -197,8 +219,8 @@ else()
|
||||
# XML_STATIC is important to avoid sg_expat_external.h
|
||||
# declaring symbols as declspec(import)
|
||||
add_definitions(-DHAVE_EXPAT_CONFIG_H -DXML_STATIC)
|
||||
set(EXPAT_INCLUDE_DIRS
|
||||
${PROJECT_SOURCE_DIR}/3rdparty/expat
|
||||
set(EXPAT_INCLUDE_DIRS
|
||||
${PROJECT_SOURCE_DIR}/3rdparty/expat
|
||||
${PROJECT_BINARY_DIR}/3rdparty/expat)
|
||||
endif(SYSTEM_EXPAT)
|
||||
|
||||
@@ -275,12 +297,12 @@ SET(CMAKE_MINSIZEREL_POSTFIX "" CACHE STRING "add a postfix, usually empty on wi
|
||||
|
||||
# isnan might not be real symbol, so can't check using function_exists
|
||||
check_cxx_source_compiles(
|
||||
"#include <cmath>
|
||||
"#include <cmath>
|
||||
int main() { return isnan(0.0);} "
|
||||
HAVE_ISNAN)
|
||||
|
||||
check_cxx_source_compiles(
|
||||
"#include <cmath>
|
||||
"#include <cmath>
|
||||
int main() { return std::isnan(0.0);} "
|
||||
HAVE_STD_ISNAN)
|
||||
|
||||
@@ -297,8 +319,12 @@ if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(WARNING_FLAGS_CXX "-Wall -Wno-overloaded-virtual")
|
||||
set(WARNING_FLAGS_C "-Wall")
|
||||
# Boost redeclares class members
|
||||
set(WARNING_FLAGS_CXX "-Wall -Wno-overloaded-virtual -Wno-redeclared-class-member")
|
||||
set(WARNING_FLAGS_C "-Wall")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
@@ -320,16 +346,16 @@ if(WIN32)
|
||||
# foreach(warning 4244 4251 4267 4275 4290 4786 4305 4996)
|
||||
# SET(WARNING_FLAGS "${WARNING_FLAGS} /wd${warning}")
|
||||
# endforeach(warning)
|
||||
|
||||
|
||||
set(MSVC_FLAGS "-DWIN32 -DNOMINMAX -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS -D__CRT_NONSTDC_NO_WARNINGS /wd4996 /wd4250 -Dstrdup=_strdup")
|
||||
if (${MSVC_VERSION} GREATER 1599)
|
||||
set( MSVC_LD_FLAGS "/FORCE:MULTIPLE" )
|
||||
endif (${MSVC_VERSION} GREATER 1599)
|
||||
endif(MSVC)
|
||||
|
||||
|
||||
# assumed on Windows
|
||||
set(HAVE_GETLOCALTIME 1)
|
||||
|
||||
|
||||
set( WINSOCK_LIBRARY "ws2_32.lib" )
|
||||
set( RT_LIBRARY "winmm" )
|
||||
endif(WIN32)
|
||||
@@ -338,15 +364,15 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS_C} ${MSVC_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS} ${BOOST_CXX_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}")
|
||||
|
||||
# use BEFORE to ensure local directories are used first,
|
||||
# use BEFORE to ensure local directories are used first,
|
||||
# ahead of system-installed libs
|
||||
include_directories(BEFORE ${PROJECT_SOURCE_DIR})
|
||||
include_directories(BEFORE ${PROJECT_SOURCE_DIR}/simgear/canvas/ShivaVG/include)
|
||||
include_directories(BEFORE ${PROJECT_BINARY_DIR}/simgear)
|
||||
|
||||
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
${OPENAL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
@@ -399,5 +425,5 @@ CONFIGURE_FILE(
|
||||
IMMEDIATE @ONLY)
|
||||
ADD_CUSTOM_TARGET(uninstall
|
||||
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace canvas
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const std::string GEO = "-geo";
|
||||
const std::string HDG = "hdg";
|
||||
const std::string Map::TYPE_NAME = "map";
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -112,87 +113,50 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
if( !boost::ends_with(child->getNameString(), GEO) )
|
||||
if( boost::ends_with(child->getNameString(), GEO) )
|
||||
_geo_nodes[child].reset(new GeoNodePair());
|
||||
else if( parent != _node && child->getNameString() == HDG )
|
||||
_hdg_nodes.insert(child);
|
||||
else
|
||||
return Element::childAdded(parent, child);
|
||||
|
||||
_geo_nodes[child].reset(new GeoNodePair());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
if( !boost::ends_with(child->getNameString(), GEO) )
|
||||
return Element::childRemoved(parent, child);
|
||||
|
||||
// TODO remove from other node
|
||||
_geo_nodes.erase(child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::valueChanged(SGPropertyNode * child)
|
||||
{
|
||||
const std::string& name = child->getNameString();
|
||||
|
||||
if( !boost::ends_with(name, GEO) )
|
||||
return Group::valueChanged(child);
|
||||
|
||||
GeoNodes::iterator it_geo_node = _geo_nodes.find(child);
|
||||
if( it_geo_node == _geo_nodes.end() )
|
||||
LOG_GEO_RET("geo node not found!")
|
||||
GeoNodePair* geo_node = it_geo_node->second.get();
|
||||
|
||||
geo_node->setDirty();
|
||||
|
||||
if( geo_node->getStatus() & GeoNodePair::INCOMPLETE )
|
||||
if( boost::ends_with(child->getNameString(), GEO) )
|
||||
// TODO remove from other node
|
||||
_geo_nodes.erase(child);
|
||||
else if( parent != _node && child->getName() == HDG )
|
||||
{
|
||||
// Detect lat, lon tuples...
|
||||
GeoCoord coord = parseGeoCoord(child->getStringValue());
|
||||
int index_other = -1;
|
||||
_hdg_nodes.erase(child);
|
||||
|
||||
switch( coord.type )
|
||||
{
|
||||
case GeoCoord::LATITUDE:
|
||||
index_other = child->getIndex() + 1;
|
||||
geo_node->setNodeLat(child);
|
||||
break;
|
||||
case GeoCoord::LONGITUDE:
|
||||
index_other = child->getIndex() - 1;
|
||||
geo_node->setNodeLon(child);
|
||||
break;
|
||||
default:
|
||||
LOG_GEO_RET("Invalid geo coord")
|
||||
}
|
||||
|
||||
SGPropertyNode *other = child->getParent()->getChild(name, index_other);
|
||||
if( !other )
|
||||
return;
|
||||
|
||||
GeoCoord coord_other = parseGeoCoord(other->getStringValue());
|
||||
if( coord_other.type == GeoCoord::INVALID
|
||||
|| coord_other.type == coord.type )
|
||||
return;
|
||||
|
||||
GeoNodes::iterator it_geo_node_other = _geo_nodes.find(other);
|
||||
if( it_geo_node_other == _geo_nodes.end() )
|
||||
LOG_GEO_RET("other geo node not found!")
|
||||
GeoNodePair* geo_node_other = it_geo_node_other->second.get();
|
||||
|
||||
// Let use both nodes use the same GeoNodePair instance
|
||||
if( geo_node_other != geo_node )
|
||||
it_geo_node_other->second = it_geo_node->second;
|
||||
|
||||
if( coord_other.type == GeoCoord::LATITUDE )
|
||||
geo_node->setNodeLat(other);
|
||||
else
|
||||
geo_node->setNodeLon(other);
|
||||
|
||||
// Set name for resulting screen coordinate nodes
|
||||
geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
|
||||
// Remove rotation matrix (tf[0]) and return to element always being
|
||||
// oriented upwards (or any orientation inside other matrices).
|
||||
child->getParent()->removeChild("tf", 0);
|
||||
}
|
||||
else
|
||||
return Element::childRemoved(parent, child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childChanged(SGPropertyNode * child)
|
||||
void Map::valueChanged(SGPropertyNode* child)
|
||||
{
|
||||
if( child->getParent() != _node )
|
||||
{
|
||||
const std::string& name = child->getNameString();
|
||||
|
||||
if( boost::ends_with(name, GEO) )
|
||||
return geoNodeChanged(child);
|
||||
else if( name == HDG )
|
||||
return hdgNodeChanged(child);
|
||||
}
|
||||
|
||||
return Group::valueChanged(child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childChanged(SGPropertyNode* child)
|
||||
{
|
||||
if( child->getParent() != _node )
|
||||
return Group::childChanged(child);
|
||||
@@ -201,8 +165,14 @@ namespace canvas
|
||||
|| child->getNameString() == "ref-lon" )
|
||||
_projection->setWorldPosition( _node->getDoubleValue("ref-lat"),
|
||||
_node->getDoubleValue("ref-lon") );
|
||||
else if( child->getNameString() == "hdg" )
|
||||
else if( child->getNameString() == HDG )
|
||||
{
|
||||
_projection->setOrientation(child->getFloatValue());
|
||||
for( NodeSet::iterator it = _hdg_nodes.begin();
|
||||
it != _hdg_nodes.end();
|
||||
++it )
|
||||
hdgNodeChanged(*it);
|
||||
}
|
||||
else if( child->getNameString() == "range" )
|
||||
_projection->setRange(child->getDoubleValue());
|
||||
else if( child->getNameString() == "screen-range" )
|
||||
@@ -213,6 +183,74 @@ namespace canvas
|
||||
_projection_dirty = true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::geoNodeChanged(SGPropertyNode* child)
|
||||
{
|
||||
GeoNodes::iterator it_geo_node = _geo_nodes.find(child);
|
||||
if( it_geo_node == _geo_nodes.end() )
|
||||
LOG_GEO_RET("GeoNode not found!")
|
||||
GeoNodePair* geo_node = it_geo_node->second.get();
|
||||
|
||||
geo_node->setDirty();
|
||||
|
||||
if( !(geo_node->getStatus() & GeoNodePair::INCOMPLETE) )
|
||||
return;
|
||||
|
||||
// Detect lat, lon tuples...
|
||||
GeoCoord coord = parseGeoCoord(child->getStringValue());
|
||||
int index_other = -1;
|
||||
|
||||
switch( coord.type )
|
||||
{
|
||||
case GeoCoord::LATITUDE:
|
||||
index_other = child->getIndex() + 1;
|
||||
geo_node->setNodeLat(child);
|
||||
break;
|
||||
case GeoCoord::LONGITUDE:
|
||||
index_other = child->getIndex() - 1;
|
||||
geo_node->setNodeLon(child);
|
||||
break;
|
||||
default:
|
||||
LOG_GEO_RET("Invalid geo coord")
|
||||
}
|
||||
|
||||
const std::string& name = child->getNameString();
|
||||
SGPropertyNode *other = child->getParent()->getChild(name, index_other);
|
||||
if( !other )
|
||||
return;
|
||||
|
||||
GeoCoord coord_other = parseGeoCoord(other->getStringValue());
|
||||
if( coord_other.type == GeoCoord::INVALID
|
||||
|| coord_other.type == coord.type )
|
||||
return;
|
||||
|
||||
GeoNodes::iterator it_geo_node_other = _geo_nodes.find(other);
|
||||
if( it_geo_node_other == _geo_nodes.end() )
|
||||
LOG_GEO_RET("other geo node not found!")
|
||||
GeoNodePair* geo_node_other = it_geo_node_other->second.get();
|
||||
|
||||
// Let use both nodes use the same GeoNodePair instance
|
||||
if( geo_node_other != geo_node )
|
||||
it_geo_node_other->second = it_geo_node->second;
|
||||
|
||||
if( coord_other.type == GeoCoord::LATITUDE )
|
||||
geo_node->setNodeLat(other);
|
||||
else
|
||||
geo_node->setNodeLon(other);
|
||||
|
||||
// Set name for resulting screen coordinate nodes
|
||||
geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::hdgNodeChanged(SGPropertyNode* child)
|
||||
{
|
||||
child->getParent()->setFloatValue(
|
||||
"tf[0]/rot",
|
||||
SGMiscf::deg2rad(child->getFloatValue() - _projection->orientation())
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Map::GeoCoord Map::parseGeoCoord(const std::string& val) const
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
@@ -59,14 +60,18 @@ namespace canvas
|
||||
typedef boost::unordered_map< SGPropertyNode*,
|
||||
boost::shared_ptr<GeoNodePair>
|
||||
> GeoNodes;
|
||||
typedef boost::unordered_set<SGPropertyNode*> NodeSet;
|
||||
|
||||
GeoNodes _geo_nodes;
|
||||
NodeSet _hdg_nodes;
|
||||
boost::shared_ptr<HorizontalProjection> _projection;
|
||||
bool _projection_dirty;
|
||||
|
||||
struct GeoCoord
|
||||
{
|
||||
GeoCoord():
|
||||
type(INVALID)
|
||||
type(INVALID),
|
||||
value(0)
|
||||
{}
|
||||
enum
|
||||
{
|
||||
@@ -77,6 +82,9 @@ namespace canvas
|
||||
double value;
|
||||
};
|
||||
|
||||
void geoNodeChanged(SGPropertyNode * child);
|
||||
void hdgNodeChanged(SGPropertyNode * child);
|
||||
|
||||
GeoCoord parseGeoCoord(const std::string& val) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -159,8 +159,12 @@ namespace canvas
|
||||
|
||||
if( empty() )
|
||||
return pos;
|
||||
|
||||
#if OSG_VERSION_LESS_THAN(3,3,5)
|
||||
GlyphQuads::Coords2 const& coords = _quads->_coords;
|
||||
#else
|
||||
GlyphQuads::Coords2 refCoords = _quads->_coords;
|
||||
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
||||
#endif
|
||||
size_t global_i = _begin + i;
|
||||
|
||||
if( global_i == _begin )
|
||||
@@ -194,7 +198,12 @@ namespace canvas
|
||||
return cursorPos(0);
|
||||
|
||||
GlyphQuads::Glyphs const& glyphs = _quads->_glyphs;
|
||||
#if OSG_VERSION_LESS_THAN(3,3,5)
|
||||
GlyphQuads::Coords2 const& coords = _quads->_coords;
|
||||
#else
|
||||
GlyphQuads::Coords2 refCoords = _quads->_coords;
|
||||
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
||||
#endif
|
||||
|
||||
float const HIT_FRACTION = 0.6;
|
||||
float const character_width = _text->getCharacterHeight()
|
||||
@@ -627,7 +636,13 @@ namespace canvas
|
||||
|
||||
const GlyphQuads& quads = _textureGlyphQuadMap.begin()->second;
|
||||
const GlyphQuads::Glyphs& glyphs = quads._glyphs;
|
||||
const GlyphQuads::Coords2& coords = quads._coords;
|
||||
#if OSG_VERSION_LESS_THAN(3,3,5)
|
||||
GlyphQuads::Coords2 const& coords = quads._coords;
|
||||
#else
|
||||
GlyphQuads::Coords2 refCoords = quads._coords;
|
||||
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
||||
#endif
|
||||
|
||||
const GlyphQuads::LineNumbers& line_numbers = quads._lineNumbers;
|
||||
|
||||
float wr = _characterHeight / getCharacterAspectRatio();
|
||||
|
||||
@@ -34,7 +34,10 @@ namespace canvas
|
||||
public:
|
||||
struct ScreenPosition
|
||||
{
|
||||
ScreenPosition() {}
|
||||
ScreenPosition():
|
||||
x(0),
|
||||
y(0)
|
||||
{}
|
||||
|
||||
ScreenPosition(double x, double y):
|
||||
x(x),
|
||||
@@ -67,8 +70,11 @@ namespace canvas
|
||||
public:
|
||||
|
||||
HorizontalProjection():
|
||||
_cos_rot(1),
|
||||
_sin_rot(0),
|
||||
_ref_lat(0),
|
||||
_ref_lon(0),
|
||||
_angle(0),
|
||||
_cos_angle(1),
|
||||
_sin_angle(0),
|
||||
_range(5)
|
||||
{
|
||||
setScreenRange(200);
|
||||
@@ -88,9 +94,19 @@ namespace canvas
|
||||
*/
|
||||
void setOrientation(float hdg)
|
||||
{
|
||||
_angle = hdg;
|
||||
|
||||
hdg = SGMiscf::deg2rad(hdg);
|
||||
_sin_rot = sin(hdg);
|
||||
_cos_rot = cos(hdg);
|
||||
_sin_angle = sin(hdg);
|
||||
_cos_angle = cos(hdg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get orientation/heading of the projection (in degree)
|
||||
*/
|
||||
float orientation() const
|
||||
{
|
||||
return _angle;
|
||||
}
|
||||
|
||||
void setRange(double range)
|
||||
@@ -114,8 +130,8 @@ namespace canvas
|
||||
pos.y *= scale;
|
||||
return ScreenPosition
|
||||
(
|
||||
_cos_rot * pos.x - _sin_rot * pos.y,
|
||||
-_sin_rot * pos.x - _cos_rot * pos.y
|
||||
_cos_angle * pos.x - _sin_angle * pos.y,
|
||||
-_sin_angle * pos.x - _cos_angle * pos.y
|
||||
);
|
||||
}
|
||||
|
||||
@@ -129,10 +145,11 @@ namespace canvas
|
||||
*/
|
||||
virtual ScreenPosition project(double lat, double lon) const = 0;
|
||||
|
||||
double _ref_lat,
|
||||
_ref_lon,
|
||||
_cos_rot,
|
||||
_sin_rot,
|
||||
double _ref_lat, ///<! Reference latitude (radian)
|
||||
_ref_lon, ///<! Reference latitude (radian)
|
||||
_angle, ///<! Map rotation angle (degree)
|
||||
_cos_angle,
|
||||
_sin_angle,
|
||||
_range;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "jupiter.hxx"
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "mars.hxx"
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "mercury.hxx"
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#ifdef __BORLANDC__
|
||||
# define exception c_exception
|
||||
#endif
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "neptune.hxx"
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "saturn.hxx"
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "uranus.hxx"
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "venus.hxx"
|
||||
|
||||
|
||||
@@ -239,7 +239,6 @@ void SVNDirectory::deleteChildByName(const std::string& nm)
|
||||
{
|
||||
DAVResource* child = dav->childWithName(nm);
|
||||
if (!child) {
|
||||
// std::cerr << "ZZZ: deleteChildByName: unknown:" << nm << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -247,17 +246,24 @@ void SVNDirectory::deleteChildByName(const std::string& nm)
|
||||
|
||||
if (child->isCollection()) {
|
||||
Dir d(path);
|
||||
d.remove(true);
|
||||
|
||||
bool ok = d.remove(true);
|
||||
if (!ok) {
|
||||
SG_LOG(SG_NETWORK, SG_ALERT, "SVNDirectory::deleteChildByName: failed to remove dir:"
|
||||
<< nm << " at path:\n\t" << path);
|
||||
}
|
||||
|
||||
DirectoryList::iterator it = findChildDir(nm);
|
||||
if (it != _children.end()) {
|
||||
SVNDirectory* c = *it;
|
||||
// std::cout << "YYY: deleting SVNDirectory for:" << nm << std::endl;
|
||||
delete c;
|
||||
_children.erase(it);
|
||||
}
|
||||
} else {
|
||||
path.remove();
|
||||
bool ok = path.remove();
|
||||
if (!ok) {
|
||||
SG_LOG(SG_NETWORK, SG_ALERT, "SVNDirectory::deleteChildByName: failed to remove path:" << nm
|
||||
<< " at path:\n\t" << path);
|
||||
}
|
||||
}
|
||||
|
||||
dav->removeChild(child);
|
||||
|
||||
@@ -251,6 +251,11 @@ NetChannelPoller::removeChannel(NetChannel* channel)
|
||||
assert(channel->poller == this);
|
||||
channel->poller = NULL;
|
||||
|
||||
// portability: MSVC throws assertion failure when empty
|
||||
if (channels.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelList::iterator it = channels.begin();
|
||||
for (; it != channels.end(); ++it) {
|
||||
if (*it == channel) {
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
|
||||
namespace simgear {
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdlib> // for atoi
|
||||
#include <algorithm>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
||||
@@ -379,6 +379,8 @@ class TestServer : public NetChannel
|
||||
public:
|
||||
TestServer()
|
||||
{
|
||||
Socket::initSockets();
|
||||
|
||||
open();
|
||||
bind(NULL, 2000); // localhost, any port
|
||||
listen(5);
|
||||
@@ -414,14 +416,14 @@ TestServer testServer;
|
||||
void waitForComplete(HTTP::Client* cl, TestRequest* tr)
|
||||
{
|
||||
SGTimeStamp start(SGTimeStamp::now());
|
||||
while (start.elapsedMSec() < 1000) {
|
||||
while (start.elapsedMSec() < 10000) {
|
||||
cl->update();
|
||||
testServer.poll();
|
||||
|
||||
if (tr->complete) {
|
||||
return;
|
||||
}
|
||||
SGTimeStamp::sleepForMSec(1);
|
||||
SGTimeStamp::sleepForMSec(15);
|
||||
}
|
||||
|
||||
cerr << "timed out" << endl;
|
||||
@@ -430,14 +432,14 @@ void waitForComplete(HTTP::Client* cl, TestRequest* tr)
|
||||
void waitForFailed(HTTP::Client* cl, TestRequest* tr)
|
||||
{
|
||||
SGTimeStamp start(SGTimeStamp::now());
|
||||
while (start.elapsedMSec() < 1000) {
|
||||
while (start.elapsedMSec() < 10000) {
|
||||
cl->update();
|
||||
testServer.poll();
|
||||
|
||||
if (tr->failed) {
|
||||
return;
|
||||
}
|
||||
SGTimeStamp::sleepForMSec(1);
|
||||
SGTimeStamp::sleepForMSec(15);
|
||||
}
|
||||
|
||||
cerr << "timed out waiting for failure" << endl;
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/sg_inlines.h>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#endif
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include <simgear/magvar/magvar.hxx>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* 2/14/00 fixed help message- dip angle (down positive), variation (E positive) */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <cmath>
|
||||
|
||||
#include <simgear/constants.h>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
include (SimGearComponent)
|
||||
|
||||
set(HEADERS
|
||||
set(HEADERS
|
||||
CSSBorder.hxx
|
||||
ListDiff.hxx
|
||||
ResourceManager.hxx
|
||||
@@ -37,6 +37,10 @@ set(SOURCES
|
||||
gzcontainerfile.cxx
|
||||
)
|
||||
|
||||
if (WINDOWS)
|
||||
list(APPEND HEADERS sgversionhelpers.hxx)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
list(APPEND SOURCES CocoaHelpers.mm)
|
||||
endif()
|
||||
|
||||
@@ -28,11 +28,12 @@ SGPath appleSpecialFolder(int dirType, int domainMask, const SGPath& def)
|
||||
{
|
||||
CocoaAutoreleasePool ap;
|
||||
NSFileManager* fm = [NSFileManager defaultManager];
|
||||
NSURL* pathUrl = [fm URLForDirectory:dirType
|
||||
inDomain:domainMask
|
||||
appropriateForURL:Nil
|
||||
create:YES
|
||||
error:nil];
|
||||
NSSearchPathDirectory d = static_cast<NSSearchPathDirectory>(dirType);
|
||||
NSURL* pathUrl = [fm URLForDirectory:d
|
||||
inDomain:domainMask
|
||||
appropriateForURL:Nil
|
||||
create:YES
|
||||
error:nil];
|
||||
if (!pathUrl) {
|
||||
return def;;
|
||||
}
|
||||
|
||||
@@ -141,8 +141,12 @@ int main(int argc, char* argv[])
|
||||
|
||||
// add
|
||||
pc.add("/opt/local");
|
||||
#ifdef _WIN32
|
||||
COMPARE(pc.str(), std::string("/usr/local/include/;/opt/local"));
|
||||
#else
|
||||
COMPARE(pc.str(), std::string("/usr/local/include/:/opt/local"));
|
||||
|
||||
#endif
|
||||
|
||||
// concat
|
||||
SGPath pd = pb;
|
||||
pd.concat("-1");
|
||||
|
||||
@@ -382,6 +382,7 @@ bool Dir::remove(bool recursive)
|
||||
|
||||
if (recursive) {
|
||||
if (!removeChildren()) {
|
||||
SG_LOG(SG_IO, SG_WARN, "Dir at:" << _path << " failed to remove children");
|
||||
return false;
|
||||
}
|
||||
} // of recursive deletion
|
||||
|
||||
@@ -56,7 +56,10 @@ static const char sgSearchPathSep = ':';
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <ShlObj.h> // for CSIDL
|
||||
#include <ShlObj.h> // for CSIDL
|
||||
// TODO: replace this include file with the official <versionhelpers.h> header
|
||||
// included in the Windows 8.1 SDK
|
||||
#include "sgversionhelpers.hxx"
|
||||
|
||||
static SGPath pathForCSIDL(int csidl, const SGPath& def)
|
||||
{
|
||||
@@ -80,6 +83,42 @@ static SGPath pathForCSIDL(int csidl, const SGPath& def)
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
static SGPath pathForKnownFolder(REFKNOWNFOLDERID folderId, const SGPath& def)
|
||||
{
|
||||
typedef HRESULT (WINAPI*PSHGKFP)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR*);
|
||||
|
||||
HINSTANCE shellDll = LoadLibrary(TEXT("shell32"));
|
||||
if (shellDll != NULL) {
|
||||
PSHGKFP pSHGetKnownFolderPath = (PSHGKFP) GetProcAddress(shellDll, "SHGetKnownFolderPath");
|
||||
if (pSHGetKnownFolderPath != NULL) {
|
||||
// system call will allocate dynamic memory... which we must release when done
|
||||
wchar_t* localFolder = 0;
|
||||
|
||||
if (pSHGetKnownFolderPath(folderId, KF_FLAG_DEFAULT_PATH, NULL, &localFolder) == S_OK) {
|
||||
// copy into local memory
|
||||
char path[MAX_PATH];
|
||||
size_t len;
|
||||
if (wcstombs_s(&len, path, localFolder, MAX_PATH) != S_OK) {
|
||||
path[0] = '\0';
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "WCS to MBS failed");
|
||||
}
|
||||
|
||||
SGPath folder_path = SGPath(path, def.getPermissionChecker());
|
||||
|
||||
// release dynamic memory
|
||||
CoTaskMemFree(static_cast<void*>(localFolder));
|
||||
|
||||
return folder_path;
|
||||
}
|
||||
}
|
||||
|
||||
FreeLibrary(shellDll);
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
#elif __APPLE__
|
||||
|
||||
// defined in CocoaHelpers.mm
|
||||
@@ -704,20 +743,35 @@ SGPath SGPath::standardLocation(StandardLocation type, const SGPath& def)
|
||||
{
|
||||
case HOME:
|
||||
return home(def);
|
||||
|
||||
#ifdef _WIN32
|
||||
case DESKTOP:
|
||||
return pathForCSIDL(CSIDL_DESKTOPDIRECTORY, def);
|
||||
case DOWNLOADS:
|
||||
// TODO use KnownFolders
|
||||
// http://msdn.microsoft.com/en-us/library/bb776911%28v=vs.85%29.aspx
|
||||
if( !def.isNull() )
|
||||
return def;
|
||||
if (IsWindowsVistaOrGreater())
|
||||
return pathForKnownFolder(FOLDERID_Desktop, def);
|
||||
|
||||
return pathForCSIDL(CSIDL_DESKTOPDIRECTORY, def);
|
||||
|
||||
case DOWNLOADS:
|
||||
if (IsWindowsVistaOrGreater())
|
||||
return pathForKnownFolder(FOLDERID_Downloads, def);
|
||||
|
||||
if (!def.isNull())
|
||||
return def;
|
||||
|
||||
return pathForCSIDL(CSIDL_DESKTOPDIRECTORY, def);
|
||||
|
||||
return pathForCSIDL(CSIDL_DESKTOPDIRECTORY, def);
|
||||
case DOCUMENTS:
|
||||
return pathForCSIDL(CSIDL_MYDOCUMENTS, def);
|
||||
if (IsWindowsVistaOrGreater())
|
||||
return pathForKnownFolder(FOLDERID_Documents, def);
|
||||
|
||||
return pathForCSIDL(CSIDL_MYDOCUMENTS, def);
|
||||
|
||||
case PICTURES:
|
||||
return pathForCSIDL(CSIDL_MYPICTURES, def);
|
||||
if (IsWindowsVistaOrGreater())
|
||||
return pathForKnownFolder(FOLDERID_Pictures, def);
|
||||
|
||||
return pathForCSIDL(CSIDL_MYPICTURES, def);
|
||||
|
||||
#elif __APPLE__
|
||||
// since this is C++, we can't include NSPathUtilities.h to access the enum
|
||||
// values, so hard-coding them here (they are stable, don't worry)
|
||||
@@ -756,20 +810,15 @@ SGPath SGPath::fromEnv(const char* name, const SGPath& def)
|
||||
return def;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
SGPath SGPath::home(const SGPath& def)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
//------------------------------------------------------------------------------
|
||||
SGPath SGPath::home(const SGPath& def)
|
||||
{
|
||||
// TODO
|
||||
return def;
|
||||
}
|
||||
return fromEnv("USERPROFILE", def);
|
||||
#else
|
||||
//------------------------------------------------------------------------------
|
||||
SGPath SGPath::home(const SGPath& def)
|
||||
{
|
||||
return fromEnv("HOME", def);
|
||||
}
|
||||
return fromEnv("HOME", def);
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
SGPath SGPath::desktop(const SGPath& def)
|
||||
|
||||
122
simgear/misc/sgversionhelpers.hxx
Normal file
122
simgear/misc/sgversionhelpers.hxx
Normal file
@@ -0,0 +1,122 @@
|
||||
// Clean drop-in replacement for the versionhelpers.h header
|
||||
//
|
||||
// Copyright (C) 2015 Alessandro Menti <alessandro.menti@hotmail.it>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#ifndef SG_VERSIONHELPERS_HXX_
|
||||
#define SG_VERSIONHELPERS_HXX_
|
||||
|
||||
#include <sdkddkver.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define VERSIONHELPERAPI inline bool
|
||||
#else
|
||||
#define VERSIONHELPERAPI FORCEINLINE BOOL
|
||||
#endif // __cplusplus
|
||||
|
||||
/* Windows 8/8.1 version numbers, not defined in the Windows 7 SDK. */
|
||||
#ifndef _WIN32_WINNT_WIN8
|
||||
#define _WIN32_WINNT_WIN8 0x0602
|
||||
#endif
|
||||
#ifndef _WIN32_WINNT_WINBLUE
|
||||
#define _WIN32_WINNT_WINBLUE 0x0603
|
||||
#endif
|
||||
|
||||
VERSIONHELPERAPI IsWindowsVersionOrGreater(WORD wMajorVersion,
|
||||
WORD wMinorVersion, WORD wServicePackMajor) {
|
||||
OSVERSIONINFOEXW osVersionInfo;
|
||||
DWORDLONG dwlConditionMask = 0;
|
||||
ZeroMemory(&osVersionInfo, sizeof(osVersionInfo));
|
||||
osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
|
||||
osVersionInfo.dwMajorVersion = wMajorVersion;
|
||||
osVersionInfo.dwMinorVersion = wMinorVersion;
|
||||
osVersionInfo.wServicePackMajor = wServicePackMajor;
|
||||
VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION,
|
||||
VER_GREATER_EQUAL);
|
||||
VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION,
|
||||
VER_GREATER_EQUAL);
|
||||
VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMAJOR,
|
||||
VER_GREATER_EQUAL);
|
||||
return VerifyVersionInfoW(&osVersionInfo, VER_MAJORVERSION
|
||||
| VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI IsWindowsXPOrGreater() {
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP),
|
||||
LOBYTE(_WIN32_WINNT_WINXP), 0);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI IsWindowsXPSP1OrGreater() {
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP),
|
||||
LOBYTE(_WIN32_WINNT_WINXP), 1);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI IsWindowsXPSP2OrGreater() {
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP),
|
||||
LOBYTE(_WIN32_WINNT_WINXP), 2);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI IsWindowsXPSP3OrGreater() {
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP),
|
||||
LOBYTE(_WIN32_WINNT_WINXP), 3);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI IsWindowsVistaOrGreater() {
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA),
|
||||
LOBYTE(_WIN32_WINNT_VISTA), 0);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI IsWindowsVistaSP1OrGreater() {
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA),
|
||||
LOBYTE(_WIN32_WINNT_VISTA), 1);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI IsWindowsVistaSP2OrGreater() {
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA),
|
||||
LOBYTE(_WIN32_WINNT_VISTA), 2);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI IsWindows7OrGreater() {
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7),
|
||||
LOBYTE(_WIN32_WINNT_WIN7), 0);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI IsWindows7SP1OrGreater() {
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7),
|
||||
LOBYTE(_WIN32_WINNT_WIN7), 1);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI IsWindows8OrGreater() {
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8),
|
||||
LOBYTE(_WIN32_WINNT_WIN8), 0);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI IsWindows8Point1OrGreater() {
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE),
|
||||
LOBYTE(_WIN32_WINNT_WINBLUE), 0);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI IsWindowsServer() {
|
||||
OSVERSIONINFOEXW osVersionInfo;
|
||||
DWORDLONG dwlConditionMask = 0;
|
||||
ZeroMemory(&osVersionInfo, sizeof(osVersionInfo));
|
||||
osVersionInfo.dwOSVersionInfoSize = sizeof(osVersionInfo);
|
||||
osVersionInfo.wProductType = VER_NT_WORKSTATION;
|
||||
VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
|
||||
return !VerifyVersionInfoW(&osVersionInfo, VER_PRODUCT_TYPE,
|
||||
dwlConditionMask);
|
||||
}
|
||||
#endif // SG_VERSIONHELPERS_HXX_
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <ctype.h>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "strutils.hxx"
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ include (SimGearComponent)
|
||||
set(HEADERS
|
||||
naref.h
|
||||
nasal.h
|
||||
iolib.h
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
@@ -26,8 +27,7 @@ set(SOURCES
|
||||
vector.c
|
||||
code.h
|
||||
data.h
|
||||
iolib.h
|
||||
parse.h
|
||||
)
|
||||
|
||||
simgear_component(nasal nasal "${SOURCES}" "${HEADERS}")
|
||||
simgear_component(nasal nasal "${SOURCES}" "${HEADERS}")
|
||||
|
||||
@@ -66,14 +66,6 @@ namespace nasal
|
||||
void GhostMetadata::addDerived(const GhostMetadata* derived)
|
||||
{
|
||||
assert(derived);
|
||||
|
||||
SG_LOG
|
||||
(
|
||||
SG_NASAL,
|
||||
SG_INFO,
|
||||
"Ghost::addDerived: " << _name_strong << " -> "
|
||||
<< derived->_name_strong
|
||||
);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
@@ -39,6 +39,12 @@ static void runNumTests( double (TestContext::*test_double)(const std::string&),
|
||||
BOOST_CHECK_EQUAL((c.*test_int)("0x755"), 0x755);
|
||||
BOOST_CHECK_EQUAL((c.*test_int)("0x055"), 0x55);
|
||||
BOOST_CHECK_EQUAL((c.*test_int)("-0x155"), -0x155);
|
||||
|
||||
BOOST_CHECK_CLOSE((c.*test_double)("2.000000953656983160"),
|
||||
2.000000953656983160, 1e-5);
|
||||
/* this value has bit pattern 0x400000007fff6789L,
|
||||
* so will look like a pointer if the endianness is set wrong
|
||||
* (see naref.h, data.h)*/
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( parse_num )
|
||||
|
||||
@@ -142,6 +142,9 @@ naRef naIOGhost(naContext c, FILE* f)
|
||||
return naNewGhost(c, &naIOGhostType, ghost);
|
||||
}
|
||||
|
||||
#if SG_NASAL_UNRESTRICTED_OPEN
|
||||
// Allows unrestricted file access, which would be a security hole
|
||||
// Replaced by the one in flightgear src/Scripting/NasalSys.cxx
|
||||
static naRef f_open(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
FILE* f;
|
||||
@@ -152,6 +155,7 @@ static naRef f_open(naContext c, naRef me, int argc, naRef* args)
|
||||
if(!f) naRuntimeError(c, strerror(errno));
|
||||
return naIOGhost(c, f);
|
||||
}
|
||||
#endif
|
||||
|
||||
// frees buffer before tossing an error
|
||||
static int getcguard(naContext ctx, FILE* f, void* buf)
|
||||
@@ -244,7 +248,9 @@ static naCFuncItem funcs[] = {
|
||||
{ "seek", f_seek },
|
||||
{ "tell", f_tell },
|
||||
{ "flush", f_flush },
|
||||
#if SG_NASAL_UNRESTRICTED_OPEN
|
||||
{ "open", f_open },
|
||||
#endif
|
||||
{ "readln", f_readln },
|
||||
{ "stat", f_stat },
|
||||
{ 0 }
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#ifndef _IOLIB_H
|
||||
#define _IOLIB_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "nasal.h"
|
||||
|
||||
@@ -33,5 +36,7 @@ extern struct naIOType naStdIOType;
|
||||
|
||||
// Defined in iolib.c, there is no "library" header to put this in
|
||||
naRef naIOGhost(naContext c, FILE* f);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
#endif // _IOLIB_H
|
||||
|
||||
@@ -1,28 +1,31 @@
|
||||
#ifndef _NAREF_H
|
||||
#define _NAREF_H
|
||||
|
||||
/* Rather than play elaborate and complicated games with
|
||||
* platform-dependent endianness headers, just detect the platforms we
|
||||
* support. This list is simpler and smaller, yet still quite
|
||||
* complete. */
|
||||
#if (defined(__x86_64) && defined(__linux__)) || defined(__sparcv9) || \
|
||||
defined(__powerpc64__)
|
||||
/* Win64 and Irix should work with this too, but have not been
|
||||
* tested */
|
||||
/* NASAL_NAN64 mode requires 64 bit pointers that only use the
|
||||
* lower 48 bits; Win64 and Irix should work with this too, but
|
||||
* have not been tested */
|
||||
# define NASAL_NAN64
|
||||
#elif defined(_M_IX86) || defined(i386) || defined(__x86_64) || \
|
||||
#elif defined(__BYTE_ORDER__)
|
||||
/* GCC and Clang define these (as a builtin, while
|
||||
* __LITTLE_ENDIAN__ requires a header), MSVC doesn't */
|
||||
# if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
|
||||
# define NASAL_LE
|
||||
# elif __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
|
||||
# define NASAL_BE
|
||||
# else
|
||||
# error Unrecognized endianness
|
||||
# endif
|
||||
#elif defined(_M_IX86) || defined(__i386) || defined(__x86_64) || \
|
||||
defined(__ia64__) || defined(_M_IA64) || defined(__ARMEL__) || \
|
||||
defined(_M_X64) || defined(__alpha__) || \
|
||||
(defined(__sh__) && defined(__LITTLE_ENDIAN__))
|
||||
defined(_M_X64) || defined(_M_ARM)
|
||||
# define NASAL_LE
|
||||
#elif defined(__sparc) || defined(__ppc__) || defined(__PPC) || \
|
||||
defined (__powerpc__) || defined (__powerpc64__) || defined (__alpha__) || \
|
||||
defined(__mips) || defined(__ARMEB__) || \
|
||||
defined(__hppa__) || defined(__s390__) || defined(__s390x__) || \
|
||||
(defined(__sh__) && !defined(__LITTLE_ENDIAN__))
|
||||
#elif defined(__sparc) || defined(__ARMEB__) || \
|
||||
defined(__hppa__) || defined(__s390__) || defined(__s390x__)
|
||||
# define NASAL_BE
|
||||
#else
|
||||
# error Unrecognized CPU architecture
|
||||
# error Unknown endianness
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
|
||||
@@ -26,3 +26,15 @@ if(ENABLE_PKGUTIL)
|
||||
add_executable(sg_pkgutil pkgutil.cxx)
|
||||
target_link_libraries(sg_pkgutil ${TEST_LIBS})
|
||||
endif()
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
|
||||
add_executable(catalog_test CatalogTest.cxx)
|
||||
target_link_libraries(catalog_test ${TEST_LIBS})
|
||||
|
||||
set_target_properties(catalog_test PROPERTIES
|
||||
COMPILE_DEFINITIONS "SRC_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\"" )
|
||||
|
||||
add_test(catalog_test ${EXECUTABLE_OUTPUT_PATH}/catalog_test)
|
||||
|
||||
endif(ENABLE_TESTS)
|
||||
@@ -33,10 +33,39 @@
|
||||
#include <simgear/package/Install.hxx>
|
||||
|
||||
namespace simgear {
|
||||
|
||||
|
||||
namespace pkg {
|
||||
|
||||
CatalogList static_catalogs;
|
||||
bool checkVersion(const std::string& aVersion, SGPropertyNode_ptr props)
|
||||
{
|
||||
BOOST_FOREACH(SGPropertyNode* v, props->getChildren("version")) {
|
||||
std::string s(v->getStringValue());
|
||||
if (s== aVersion) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// allow 3.5.* to match any of 3.5.0, 3.5.1rc1, 3.5.11 or so on
|
||||
if (strutils::ends_with(s, ".*")) {
|
||||
size_t lastDot = aVersion.rfind('.');
|
||||
std::string ver = aVersion.substr(0, lastDot);
|
||||
if (ver == s.substr(0, s.length() - 2)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string redirectUrlForVersion(const std::string& aVersion, SGPropertyNode_ptr props)
|
||||
{
|
||||
BOOST_FOREACH(SGPropertyNode* v, props->getChildren("alternate-version")) {
|
||||
if (v->getStringValue("version") == aVersion) {
|
||||
return v->getStringValue("url");
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -46,25 +75,28 @@ public:
|
||||
Downloader(CatalogRef aOwner, const std::string& aUrl) :
|
||||
HTTP::Request(aUrl),
|
||||
m_owner(aOwner)
|
||||
{
|
||||
{
|
||||
// refreshing
|
||||
m_owner->changeStatus(Delegate::FAIL_IN_PROGRESS);
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
virtual void gotBodyData(const char* s, int n)
|
||||
{
|
||||
m_buffer += std::string(s, n);
|
||||
}
|
||||
|
||||
|
||||
virtual void onDone()
|
||||
{
|
||||
{
|
||||
if (responseCode() != 200) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "catalog download failure:" << m_owner->url());
|
||||
m_owner->refreshComplete(Delegate::FAIL_DOWNLOAD);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SGPropertyNode* props = new SGPropertyNode;
|
||||
|
||||
|
||||
try {
|
||||
readProperties(m_buffer.data(), m_buffer.size(), props);
|
||||
m_owner->parseProps(props);
|
||||
@@ -73,15 +105,29 @@ protected:
|
||||
m_owner->refreshComplete(Delegate::FAIL_EXTRACT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
std::string ver(m_owner->root()->catalogVersion());
|
||||
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);
|
||||
m_owner->refreshComplete(Delegate::FAIL_VERSION);
|
||||
|
||||
// check for a version redirect entry
|
||||
std::string url = redirectUrlForVersion(ver, props);
|
||||
if (!url.empty()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "redirecting from " << m_owner->url() <<
|
||||
" to \n\t" << url);
|
||||
|
||||
// update the URL and kick off a new request
|
||||
m_owner->m_url = url;
|
||||
Downloader* dl = new Downloader(m_owner, url);
|
||||
m_owner->root()->makeHTTPRequest(dl);
|
||||
} else {
|
||||
m_owner->refreshComplete(Delegate::FAIL_VERSION);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
} // of version check failed
|
||||
|
||||
// cache the catalog data, now we have a valid install root
|
||||
Dir d(m_owner->installRoot());
|
||||
SGPath p = d.file("catalog.xml");
|
||||
@@ -89,45 +135,29 @@ protected:
|
||||
std::ofstream f(p.c_str(), std::ios::out | std::ios::trunc);
|
||||
f.write(m_buffer.data(), m_buffer.size());
|
||||
f.close();
|
||||
|
||||
|
||||
time(&m_owner->m_retrievedTime);
|
||||
m_owner->writeTimestamp();
|
||||
m_owner->refreshComplete(Delegate::FAIL_SUCCESS);
|
||||
m_owner->refreshComplete(Delegate::CATALOG_REFRESHED);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
bool checkVersion(const std::string& aVersion, SGPropertyNode* aProps)
|
||||
{
|
||||
BOOST_FOREACH(SGPropertyNode* v, aProps->getChildren("version")) {
|
||||
if (v->getStringValue() == aVersion) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
CatalogRef m_owner;
|
||||
std::string m_buffer;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CatalogList Catalog::allCatalogs()
|
||||
{
|
||||
return static_catalogs;
|
||||
}
|
||||
|
||||
Catalog::Catalog(Root *aRoot) :
|
||||
m_root(aRoot),
|
||||
m_status(Delegate::FAIL_UNKNOWN),
|
||||
m_retrievedTime(0)
|
||||
{
|
||||
static_catalogs.push_back(this);
|
||||
}
|
||||
|
||||
Catalog::~Catalog()
|
||||
{
|
||||
CatalogList::iterator it = std::find(static_catalogs.begin(), static_catalogs.end(), this);
|
||||
static_catalogs.erase(it);
|
||||
}
|
||||
|
||||
CatalogRef Catalog::createFromUrl(Root* aRoot, const std::string& aUrl)
|
||||
@@ -136,10 +166,10 @@ CatalogRef Catalog::createFromUrl(Root* aRoot, const std::string& aUrl)
|
||||
c->m_url = aUrl;
|
||||
Downloader* dl = new Downloader(c, aUrl);
|
||||
aRoot->makeHTTPRequest(dl);
|
||||
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
CatalogRef Catalog::createFromPath(Root* aRoot, const SGPath& aPath)
|
||||
{
|
||||
SGPath xml = aPath;
|
||||
@@ -147,29 +177,66 @@ CatalogRef Catalog::createFromPath(Root* aRoot, const SGPath& aPath)
|
||||
if (!xml.exists()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
SGPropertyNode_ptr props;
|
||||
try {
|
||||
props = new SGPropertyNode;
|
||||
readProperties(xml.str(), props);
|
||||
} catch (sg_exception& e) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (props->getStringValue("version") != aRoot->catalogVersion()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "skipping catalog at " << aPath << ", version mismatch:\n\t"
|
||||
<< props->getStringValue("version") << " vs required " << aRoot->catalogVersion());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (!checkVersion(aRoot->catalogVersion(), props)) {
|
||||
std::string redirect = redirectUrlForVersion(aRoot->catalogVersion(), props);
|
||||
if (!redirect.empty()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "catalog at " << aPath << ", version mismatch:\n\t"
|
||||
<< "redirecting to alternate URL:" << redirect);
|
||||
CatalogRef c = Catalog::createFromUrl(aRoot, redirect);
|
||||
c->m_installRoot = aPath;
|
||||
return c;
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "skipping catalog at " << aPath << ", version mismatch:\n\t"
|
||||
<< props->getStringValue("version") << " vs required " << aRoot->catalogVersion());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CatalogRef c = new Catalog(aRoot);
|
||||
c->m_installRoot = aPath;
|
||||
c->parseProps(props);
|
||||
c->parseProps(props); // will set status
|
||||
c->parseTimestamp();
|
||||
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
bool Catalog::uninstall()
|
||||
{
|
||||
bool ok;
|
||||
bool atLeastOneFailure = false;
|
||||
|
||||
BOOST_FOREACH(PackageRef p, installedPackages()) {
|
||||
ok = p->existingInstall()->uninstall();
|
||||
if (!ok) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "uninstall of package " <<
|
||||
p->id() << " failed");
|
||||
// continue trying other packages, bailing out here
|
||||
// gains us nothing
|
||||
atLeastOneFailure = true;
|
||||
}
|
||||
}
|
||||
|
||||
Dir d(m_installRoot);
|
||||
ok = d.remove(true /* recursive */);
|
||||
if (!ok) {
|
||||
atLeastOneFailure = true;
|
||||
}
|
||||
|
||||
changeStatus(atLeastOneFailure ? Delegate::FAIL_FILESYSTEM
|
||||
: Delegate::FAIL_SUCCESS);
|
||||
return ok;
|
||||
}
|
||||
|
||||
PackageList const&
|
||||
Catalog::packages() const
|
||||
{
|
||||
@@ -196,7 +263,7 @@ Catalog::packagesNeedingUpdate() const
|
||||
if (!p->isInstalled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (p->install()->hasUpdate()) {
|
||||
r.push_back(p);
|
||||
}
|
||||
@@ -215,7 +282,7 @@ Catalog::installedPackages() const
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
InstallRef Catalog::installForPackage(PackageRef pkg) const
|
||||
{
|
||||
PackageInstallDict::const_iterator it = m_installed.find(pkg);
|
||||
@@ -226,16 +293,17 @@ InstallRef Catalog::installForPackage(PackageRef pkg) const
|
||||
if (p.exists()) {
|
||||
return Install::createFromPath(p, CatalogRef(const_cast<Catalog*>(this)));
|
||||
}
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
||||
void Catalog::refresh()
|
||||
{
|
||||
Downloader* dl = new Downloader(this, url());
|
||||
// will iupdate status to IN_PROGRESS
|
||||
m_root->makeHTTPRequest(dl);
|
||||
m_root->catalogRefreshBegin(this);
|
||||
}
|
||||
@@ -294,16 +362,19 @@ void Catalog::parseProps(const SGPropertyNode* aProps)
|
||||
<< " is now at: " << m_props->getStringValue("url"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_url = m_props->getStringValue("url");
|
||||
|
||||
if (m_installRoot.isNull()) {
|
||||
m_installRoot = m_root->path();
|
||||
m_installRoot.append(id());
|
||||
|
||||
|
||||
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
|
||||
@@ -331,7 +402,7 @@ std::string Catalog::description() const
|
||||
{
|
||||
return getLocalisedString(m_props, "description");
|
||||
}
|
||||
|
||||
|
||||
SGPropertyNode* Catalog::properties() const
|
||||
{
|
||||
return m_props.ptr();
|
||||
@@ -366,7 +437,7 @@ bool Catalog::needsRefresh() const
|
||||
unsigned int maxAge = m_props->getIntValue("max-age-sec", m_root->maxAgeSeconds());
|
||||
return (ageInSeconds() > maxAge);
|
||||
}
|
||||
|
||||
|
||||
std::string Catalog::getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const
|
||||
{
|
||||
if (aRoot->hasChild(m_root->getLocale())) {
|
||||
@@ -375,13 +446,14 @@ std::string Catalog::getLocalisedString(const SGPropertyNode* aRoot, const char*
|
||||
return localeRoot->getStringValue(aName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return aRoot->getStringValue(aName);
|
||||
}
|
||||
|
||||
void Catalog::refreshComplete(Delegate::FailureCode aReason)
|
||||
{
|
||||
m_root->catalogRefreshComplete(this, aReason);
|
||||
changeStatus(aReason);
|
||||
}
|
||||
|
||||
void Catalog::registerInstall(Install* ins)
|
||||
@@ -389,7 +461,7 @@ void Catalog::registerInstall(Install* ins)
|
||||
if (!ins || ins->package()->catalog() != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_installed[ins->package()] = ins;
|
||||
}
|
||||
|
||||
@@ -398,10 +470,30 @@ void Catalog::unregisterInstall(Install* ins)
|
||||
if (!ins || ins->package()->catalog() != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
m_installed.erase(ins->package());
|
||||
}
|
||||
|
||||
void Catalog::changeStatus(Delegate::FailureCode newStatus)
|
||||
{
|
||||
if (m_status == newStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_status = newStatus;
|
||||
m_statusCallbacks(this);
|
||||
}
|
||||
|
||||
void Catalog::addStatusCallback(const Callback& cb)
|
||||
{
|
||||
m_statusCallbacks.push_back(cb);
|
||||
}
|
||||
|
||||
Delegate::FailureCode Catalog::status() const
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
} // of namespace pkg
|
||||
|
||||
} // of namespace simgear
|
||||
|
||||
@@ -22,19 +22,22 @@
|
||||
#include <ctime>
|
||||
#include <map>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
|
||||
#include <simgear/structure/SGReferenced.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/structure/function_list.hxx>
|
||||
|
||||
#include <simgear/package/Delegate.hxx>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
|
||||
namespace HTTP { class Client; }
|
||||
|
||||
|
||||
namespace pkg
|
||||
{
|
||||
|
||||
@@ -43,11 +46,11 @@ class Package;
|
||||
class Catalog;
|
||||
class Root;
|
||||
class Install;
|
||||
|
||||
|
||||
typedef SGSharedPtr<Package> PackageRef;
|
||||
typedef SGSharedPtr<Catalog> CatalogRef;
|
||||
typedef SGSharedPtr<Install> InstallRef;
|
||||
|
||||
|
||||
typedef std::vector<PackageRef> PackageList;
|
||||
typedef std::vector<CatalogRef> CatalogList;
|
||||
|
||||
@@ -55,15 +58,18 @@ class Catalog : public SGReferenced
|
||||
{
|
||||
public:
|
||||
virtual ~Catalog();
|
||||
|
||||
|
||||
static CatalogRef createFromUrl(Root* aRoot, const std::string& aUrl);
|
||||
|
||||
|
||||
static CatalogRef createFromPath(Root* aRoot, const SGPath& aPath);
|
||||
|
||||
static CatalogList allCatalogs();
|
||||
|
||||
|
||||
Root* root() const
|
||||
{ return m_root;};
|
||||
|
||||
/**
|
||||
* uninstall this catalog entirely, including all installed packages
|
||||
*/
|
||||
bool uninstall();
|
||||
|
||||
/**
|
||||
* perform a refresh of the catalog contents
|
||||
@@ -89,70 +95,87 @@ public:
|
||||
/**
|
||||
* retrieve all the packages in the catalog which are installed
|
||||
* and have a pendig update
|
||||
*/
|
||||
*/
|
||||
PackageList packagesNeedingUpdate() const;
|
||||
|
||||
|
||||
SGPath installRoot() const
|
||||
{ return m_installRoot; }
|
||||
|
||||
|
||||
std::string id() const;
|
||||
|
||||
|
||||
std::string url() const;
|
||||
|
||||
|
||||
std::string description() const;
|
||||
|
||||
|
||||
PackageRef getPackageById(const std::string& aId) const;
|
||||
|
||||
|
||||
InstallRef installForPackage(PackageRef pkg) const;
|
||||
|
||||
|
||||
/**
|
||||
* test if the catalog data was retrieved longer ago than the
|
||||
* maximum permitted age for this catalog.
|
||||
*/
|
||||
bool needsRefresh() const;
|
||||
|
||||
|
||||
unsigned int ageInSeconds() const;
|
||||
|
||||
|
||||
/**
|
||||
* access the raw property data in the catalog
|
||||
*/
|
||||
SGPropertyNode* properties() const;
|
||||
|
||||
Delegate::FailureCode status() const;
|
||||
|
||||
typedef boost::function<void(Catalog*)> Callback;
|
||||
|
||||
void addStatusCallback(const Callback& cb);
|
||||
|
||||
template<class C>
|
||||
void addStatusCallback(C* instance, void (C::*mem_func)(Catalog*))
|
||||
{
|
||||
return addStatusCallback(boost::bind(mem_func, instance, _1));
|
||||
}
|
||||
private:
|
||||
Catalog(Root* aRoot);
|
||||
|
||||
|
||||
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 parseTimestamp();
|
||||
void writeTimestamp();
|
||||
|
||||
|
||||
std::string getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const;
|
||||
|
||||
|
||||
void changeStatus(Delegate::FailureCode newStatus);
|
||||
|
||||
Root* m_root;
|
||||
SGPropertyNode_ptr m_props;
|
||||
SGPath m_installRoot;
|
||||
std::string m_url;
|
||||
|
||||
Delegate::FailureCode m_status;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} // of namespace pkg
|
||||
|
||||
} // of namespace simgear
|
||||
|
||||
107
simgear/package/CatalogTest.cxx
Normal file
107
simgear/package/CatalogTest.cxx
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright (C) 2015 James Turner - zakalawe@mac.com
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/misc/test_macros.hxx>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include <simgear/package/Catalog.hxx>
|
||||
#include <simgear/package/Root.hxx>
|
||||
#include <simgear/package/Package.hxx>
|
||||
|
||||
#include <simgear/misc/sg_dir.hxx>
|
||||
|
||||
using namespace simgear;
|
||||
|
||||
int parseTest()
|
||||
{
|
||||
SGPath rootPath = simgear::Dir::current().path();
|
||||
rootPath.append("testRoot");
|
||||
pkg::Root* root = new pkg::Root(rootPath, "8.1.12");
|
||||
pkg::CatalogRef cat = pkg::Catalog::createFromPath(root, SGPath(SRC_DIR "/catalogTest1"));
|
||||
|
||||
VERIFY(cat.valid());
|
||||
|
||||
COMPARE(cat->id(), "org.flightgear.test.catalog1");
|
||||
COMPARE(cat->url(), "http://download.flightgear.org/catalog1/catalog.xml");
|
||||
COMPARE(cat->description(), "First test catalog");
|
||||
|
||||
// check the packages too
|
||||
COMPARE(cat->packages().size(), 3);
|
||||
|
||||
pkg::PackageRef p1 = cat->packages().front();
|
||||
COMPARE(p1->catalog(), cat.ptr());
|
||||
|
||||
COMPARE(p1->id(), "alpha");
|
||||
COMPARE(p1->qualifiedId(), "org.flightgear.test.catalog1.alpha");
|
||||
COMPARE(p1->name(), "Alpha package");
|
||||
COMPARE(p1->revision(), 8);
|
||||
COMPARE(p1->fileSizeBytes(), 1234567);
|
||||
|
||||
|
||||
pkg::PackageRef p2 = cat->getPackageById("c172p");
|
||||
VERIFY(p2.valid());
|
||||
COMPARE(p2->qualifiedId(), "org.flightgear.test.catalog1.c172p");
|
||||
COMPARE(p2->description(), "A plane made by Cessna");
|
||||
|
||||
|
||||
|
||||
// test filtering / searching too
|
||||
string_set tags(p2->tags());
|
||||
COMPARE(tags.size(), 4);
|
||||
VERIFY(tags.find("ifr") != tags.end());
|
||||
VERIFY(tags.find("cessna") != tags.end());
|
||||
VERIFY(tags.find("jet") == tags.end());
|
||||
|
||||
|
||||
SGPropertyNode_ptr queryA(new SGPropertyNode);
|
||||
queryA->setStringValue("tag", "ifr");
|
||||
VERIFY(p2->matches(queryA.ptr()));
|
||||
|
||||
SGPropertyNode_ptr queryB(new SGPropertyNode);
|
||||
queryB->setStringValue("name", "ces");
|
||||
VERIFY(p2->matches(queryB.ptr()));
|
||||
|
||||
SGPropertyNode_ptr queryC(new SGPropertyNode);
|
||||
queryC->setStringValue("name", "foo");
|
||||
VERIFY(!p2->matches(queryC.ptr()));
|
||||
|
||||
SGPropertyNode_ptr queryD(new SGPropertyNode);
|
||||
queryD->setIntValue("rating-FDM", 3);
|
||||
VERIFY(p2->matches(queryD.ptr()));
|
||||
|
||||
SGPropertyNode_ptr queryE(new SGPropertyNode);
|
||||
queryE->setIntValue("rating-model", 5);
|
||||
queryE->setStringValue("description", "cessna");
|
||||
VERIFY(p2->matches(queryE.ptr()));
|
||||
|
||||
|
||||
delete root;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
parseTest();
|
||||
std::cout << "Successfully passed all tests!" << std::endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -42,7 +42,8 @@ public:
|
||||
FAIL_DOWNLOAD, ///< network issue
|
||||
FAIL_EXTRACT, ///< package archive failed to extract cleanly
|
||||
FAIL_FILESYSTEM, ///< unknown filesystem error occurred
|
||||
FAIL_VERSION ///< version check mismatch
|
||||
FAIL_VERSION, ///< version check mismatch
|
||||
CATALOG_REFRESHED
|
||||
} FailureCode;
|
||||
|
||||
|
||||
|
||||
@@ -313,11 +313,21 @@ void Install::startUpdate()
|
||||
m_package->catalog()->root()->startInstall(this);
|
||||
}
|
||||
|
||||
void Install::uninstall()
|
||||
bool Install::uninstall()
|
||||
{
|
||||
Dir d(m_path);
|
||||
d.remove(true);
|
||||
if (!d.remove(true)) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "package uninstall failed: couldn't remove path " << m_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_package->catalog()->unregisterInstall(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Install::isDownloading() const
|
||||
{
|
||||
return (m_download != NULL);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -73,9 +73,11 @@ public:
|
||||
bool hasUpdate() const;
|
||||
|
||||
void startUpdate();
|
||||
|
||||
void uninstall();
|
||||
|
||||
bool uninstall();
|
||||
|
||||
bool isDownloading() const;
|
||||
|
||||
/**
|
||||
* Set the handler to be called when the installation successfully
|
||||
* completes.
|
||||
|
||||
@@ -186,6 +186,11 @@ std::string Package::description() const
|
||||
{
|
||||
return getLocalisedProp("description");
|
||||
}
|
||||
|
||||
string_set Package::tags() const
|
||||
{
|
||||
return m_tags;
|
||||
}
|
||||
|
||||
SGPropertyNode* Package::properties() const
|
||||
{
|
||||
@@ -238,7 +243,7 @@ PackageList Package::dependencies() const
|
||||
|
||||
// prefer local hangar package if possible, in case someone does something
|
||||
// silly with naming. Of course flightgear's aircraft search doesn't know
|
||||
// about hanagrs, so names still need to be unique.
|
||||
// about hangars, so names still need to be unique.
|
||||
PackageRef depPkg = m_catalog->getPackageById(depName);
|
||||
if (!depPkg) {
|
||||
Root* rt = m_catalog->root();
|
||||
|
||||
@@ -112,7 +112,9 @@ public:
|
||||
{ return m_catalog; }
|
||||
|
||||
bool matches(const SGPropertyNode* aFilter) const;
|
||||
|
||||
|
||||
string_set tags() const;
|
||||
|
||||
/**
|
||||
* download URLs for the package
|
||||
*/
|
||||
|
||||
@@ -336,6 +336,28 @@ void Root::catalogRefreshComplete(CatalogRef aCat, Delegate::FailureCode aReason
|
||||
}
|
||||
}
|
||||
|
||||
bool Root::removeCatalogById(const std::string& aId)
|
||||
{
|
||||
CatalogDict::iterator catIt = d->catalogs.find(aId);
|
||||
if (catIt == d->catalogs.end()) {
|
||||
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");
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
} // of namespace pkg
|
||||
|
||||
} // of namespace simgear
|
||||
|
||||
@@ -109,6 +109,12 @@ public:
|
||||
CatalogRef getCatalogById(const std::string& aId) const;
|
||||
|
||||
void scheduleToUpdate(InstallRef aInstall);
|
||||
|
||||
/**
|
||||
* remove a catalog. Will uninstall all packages originating
|
||||
* from the catalog too.
|
||||
*/
|
||||
bool removeCatalogById(const std::string& aId);
|
||||
private:
|
||||
friend class Install;
|
||||
friend class Catalog;
|
||||
|
||||
64
simgear/package/catalogTest1/catalog.xml
Normal file
64
simgear/package/catalogTest1/catalog.xml
Normal file
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<PropertyList>
|
||||
<id>org.flightgear.test.catalog1</id>
|
||||
<description>First test catalog</description>
|
||||
<url>http://download.flightgear.org/catalog1/catalog.xml</url>
|
||||
<version>8.1.*</version>
|
||||
<version>8.0.0</version>
|
||||
<version>8.2.0</version>
|
||||
|
||||
<package>
|
||||
<id>alpha</id>
|
||||
<name>Alpha package</name>
|
||||
<revision type="int">8</revision>
|
||||
<file-size-bytes type="int">1234567</file-size-bytes>
|
||||
</package>
|
||||
|
||||
<package>
|
||||
<id>c172p</id>
|
||||
<name>Cessna 172-P</name>
|
||||
<description>A plane made by Cessna</description>
|
||||
<revision type="int">42</revision>
|
||||
<file-size-bytes type="int">34567</file-size-bytes>
|
||||
|
||||
<tag>cessna</tag>
|
||||
<tag>ga</tag>
|
||||
<tag>piston</tag>
|
||||
<tag>ifr</tag>
|
||||
|
||||
<rating>
|
||||
<FDM type="int">3</FDM>
|
||||
<systems type="int">4</systems>
|
||||
<model type="int">5</model>
|
||||
<cockpit type="int">4</cockpit>
|
||||
</rating>
|
||||
|
||||
<!-- local dependency -->
|
||||
<depends>
|
||||
<id>org.flightgear.test.catalog1.common-sounds</id>
|
||||
<revision>10</revision>
|
||||
</depends>
|
||||
|
||||
<variant>
|
||||
<id>c172p-2d-panel</id>
|
||||
<name>C172 with 2d panel only</name>
|
||||
</variant>
|
||||
|
||||
<variant>
|
||||
<id>c172p-floats</id>
|
||||
<name>C172 with floats</name>
|
||||
</variant>
|
||||
|
||||
<variant>
|
||||
<id>c172p-skis</id>
|
||||
<name>C172 with skis</name>
|
||||
</variant>
|
||||
</package>
|
||||
|
||||
<package>
|
||||
<id>common-sounds</id>
|
||||
<name>Common sound files for test catalog aircraft</name>
|
||||
<revision>10</revision>
|
||||
</package>
|
||||
</PropertyList>
|
||||
@@ -158,7 +158,8 @@ SG_MD5Transform(u_int32_t state[4], const u_int8_t block[MD5_BLOCK_LENGTH])
|
||||
{
|
||||
u_int32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4];
|
||||
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
#if ((defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || \
|
||||
defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM) )
|
||||
memcpy(in, block, sizeof(in));
|
||||
#else
|
||||
for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) {
|
||||
@@ -247,4 +248,4 @@ SG_MD5Transform(u_int32_t state[4], const u_int8_t block[MD5_BLOCK_LENGTH])
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
using namespace simgear;
|
||||
using namespace simgear;
|
||||
using namespace std;
|
||||
|
||||
bool keepRunning = true;
|
||||
@@ -37,29 +37,29 @@ public:
|
||||
virtual void refreshComplete()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual void failedRefresh(pkg::Catalog* aCatalog, FailureCode aReason)
|
||||
{
|
||||
cerr << "failed refresh of " << aCatalog->description() << ":" << aReason << endl;
|
||||
}
|
||||
|
||||
|
||||
virtual void startInstall(pkg::Install* aInstall)
|
||||
{
|
||||
_lastPercent = 999;
|
||||
cout << "starting install of " << aInstall->package()->name() << endl;
|
||||
}
|
||||
|
||||
|
||||
virtual void installProgress(pkg::Install* aInstall, unsigned int bytes, unsigned int total)
|
||||
{
|
||||
unsigned int percent = (bytes * 100) / total;
|
||||
if (percent == _lastPercent) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_lastPercent = percent;
|
||||
cout << percent << "%" << endl;
|
||||
}
|
||||
|
||||
|
||||
virtual void finishInstall(pkg::Install* aInstall)
|
||||
{
|
||||
cout << "done install of " << aInstall->package()->name() << endl;
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
}
|
||||
private:
|
||||
unsigned int _lastPercent;
|
||||
|
||||
|
||||
};
|
||||
|
||||
void printRating(pkg::Package* pkg, const std::string& aRating, const std::string& aLabel)
|
||||
@@ -87,24 +87,24 @@ void printPackageInfo(pkg::Package* pkg)
|
||||
cout << "Name:" << pkg->name() << endl;
|
||||
cout << "Description:" << pkg->description() << endl;
|
||||
cout << "Long description:\n" << pkg->getLocalisedProp("long-description") << endl << endl;
|
||||
|
||||
|
||||
if (pkg->properties()->hasChild("author")) {
|
||||
cout << "Authors:" << endl;
|
||||
BOOST_FOREACH(SGPropertyNode* author, pkg->properties()->getChildren("author")) {
|
||||
if (author->hasChild("name")) {
|
||||
cout << "\t" << author->getStringValue("name") << endl;
|
||||
|
||||
|
||||
} else {
|
||||
// simple author structure
|
||||
cout << "\t" << author->getStringValue() << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
|
||||
cout << "Ratings:" << endl;
|
||||
printRating(pkg, "fdm", "Flight-model ");
|
||||
printRating(pkg, "cockpit", "Cockpit ");
|
||||
@@ -117,15 +117,15 @@ int main(int argc, char** argv)
|
||||
|
||||
HTTP::Client* http = new HTTP::Client();
|
||||
pkg::Root* root = new pkg::Root(Dir::current().path(), "");
|
||||
|
||||
|
||||
MyDelegate dlg;
|
||||
root->setDelegate(&dlg);
|
||||
|
||||
|
||||
cout << "Package root is:" << Dir::current().path() << endl;
|
||||
cout << "have " << pkg::Catalog::allCatalogs().size() << " catalog(s)" << endl;
|
||||
|
||||
cout << "have " << root->catalogs().size() << " catalog(s)" << endl;
|
||||
|
||||
root->setHTTPClient(http);
|
||||
|
||||
|
||||
if (!strcmp(argv[1], "add")) {
|
||||
std::string url(argv[2]);
|
||||
pkg::Catalog::createFromUrl(root, url);
|
||||
@@ -137,12 +137,12 @@ int main(int argc, char** argv)
|
||||
cerr << "unknown package:" << argv[2] << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
if (pkg->isInstalled()) {
|
||||
cout << "package " << pkg->id() << " is already installed at " << pkg->install()->path() << endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
pkg::CatalogRef catalog = pkg->catalog();
|
||||
cout << "Will install:" << pkg->id() << " from " << catalog->id() <<
|
||||
"(" << catalog->description() << ")" << endl;
|
||||
@@ -153,12 +153,12 @@ int main(int argc, char** argv)
|
||||
cerr << "unknown package:" << argv[2] << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
if (!pkg->isInstalled()) {
|
||||
cerr << "package " << argv[2] << " not installed" << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
cout << "Will uninstall:" << pkg->id() << endl;
|
||||
pkg->install()->uninstall();
|
||||
} else if (!strcmp(argv[1], "update-all")) {
|
||||
@@ -172,7 +172,7 @@ int main(int argc, char** argv)
|
||||
cout << "no packages with updates" << endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
cout << updates.size() << " packages have updates" << endl;
|
||||
BOOST_FOREACH(pkg::Package* p, updates) {
|
||||
cout << "\t" << p->id() << " " << p->getLocalisedProp("name") << endl;
|
||||
@@ -183,13 +183,13 @@ int main(int argc, char** argv)
|
||||
cerr << "unknown package:" << argv[2] << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
printPackageInfo(pkg);
|
||||
} else {
|
||||
cerr << "unknown command:" << argv[1] << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
while (http->hasActiveRequests()) {
|
||||
http->update();
|
||||
}
|
||||
|
||||
@@ -144,9 +144,9 @@ public:
|
||||
|
||||
#undef SG_DEF_ASSIGN_OP
|
||||
|
||||
SGPropertyNode* node() const
|
||||
SGPropertyNode* node(bool aCreate = false) const
|
||||
{
|
||||
return PropertyObjectBase::node(false);
|
||||
return PropertyObjectBase::node(aCreate);
|
||||
}
|
||||
}; // of template PropertyObject
|
||||
|
||||
@@ -237,9 +237,9 @@ public:
|
||||
return (s == value);
|
||||
}
|
||||
|
||||
SGPropertyNode* node() const
|
||||
SGPropertyNode* node(bool aCreate = false) const
|
||||
{
|
||||
return PropertyObjectBase::node(false);
|
||||
return PropertyObjectBase::node(aCreate);
|
||||
}
|
||||
private:
|
||||
};
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <boost/iterator/iterator_adaptor.hpp>
|
||||
|
||||
#include "Effect.hxx"
|
||||
#include "mat.hxx"
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
@@ -69,6 +70,8 @@ class EffectGeode : public osg::Geode
|
||||
META_Node(simgear,EffectGeode);
|
||||
Effect* getEffect() const { return _effect.get(); }
|
||||
void setEffect(Effect* effect);
|
||||
SGMaterial* getMaterial() const { return _material; }
|
||||
void setMaterial(SGMaterial* mat) { _material = mat; }
|
||||
virtual void resizeGLObjectBuffers(unsigned int maxSize);
|
||||
virtual void releaseGLObjects(osg::State* = 0) const;
|
||||
|
||||
@@ -83,6 +86,7 @@ class EffectGeode : public osg::Geode
|
||||
void runGenerators(osg::Geometry *geometry);
|
||||
private:
|
||||
osg::ref_ptr<Effect> _effect;
|
||||
SGMaterial* _material;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -326,9 +326,15 @@ public:
|
||||
= GL2Extensions::Get(static_cast<unsigned>(contextId), true);
|
||||
if (!extensions)
|
||||
return;
|
||||
#if OSG_VERSION_LESS_THAN(3,3,4)
|
||||
if (!extensions->isGlslSupported())
|
||||
return;
|
||||
value = extensions->getLanguageVersion();
|
||||
#else
|
||||
if (!extensions->isGlslSupported)
|
||||
return;
|
||||
value = extensions->glslLanguageVersion;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
@@ -357,7 +363,11 @@ public:
|
||||
= GL2Extensions::Get(static_cast<unsigned>(contextId), true);
|
||||
if (!extensions)
|
||||
return;
|
||||
#if OSG_VERSION_LESS_THAN(3,3,4)
|
||||
value = extensions->isGlslSupported();
|
||||
#else
|
||||
value = extensions->isGlslSupported;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -323,6 +323,7 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
||||
|
||||
// Random vegetation properties
|
||||
wood_coverage = props->getDoubleValue("wood-coverage", 0.0);
|
||||
tree_effect = props->getStringValue("tree-effect", "Effects/tree");
|
||||
tree_height = props->getDoubleValue("tree-height-m", 0.0);
|
||||
tree_width = props->getDoubleValue("tree-width-m", 0.0);
|
||||
tree_range = props->getDoubleValue("tree-range-m", 0.0);
|
||||
@@ -441,7 +442,7 @@ Effect* SGMaterial::get_effect(int i)
|
||||
return _status[i].effect.get();
|
||||
}
|
||||
|
||||
Effect* SGMaterial::get_effect(const SGTexturedTriangleBin& triangleBin)
|
||||
Effect* SGMaterial::get_one_effect(int texIndex)
|
||||
{
|
||||
SGGuard<SGMutex> g(_lock);
|
||||
if (_status.empty()) {
|
||||
@@ -449,7 +450,7 @@ Effect* SGMaterial::get_effect(const SGTexturedTriangleBin& triangleBin)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i = triangleBin.getTextureIndex() % _status.size();
|
||||
int i = texIndex % _status.size();
|
||||
return get_effect(i);
|
||||
}
|
||||
|
||||
@@ -460,7 +461,7 @@ Effect* SGMaterial::get_effect()
|
||||
}
|
||||
|
||||
|
||||
osg::Texture2D* SGMaterial::get_object_mask(const SGTexturedTriangleBin& triangleBin)
|
||||
osg::Texture2D* SGMaterial::get_one_object_mask(int texIndex)
|
||||
{
|
||||
if (_status.empty()) {
|
||||
SG_LOG( SG_GENERAL, SG_WARN, "No mask available.");
|
||||
@@ -469,7 +470,7 @@ osg::Texture2D* SGMaterial::get_object_mask(const SGTexturedTriangleBin& triangl
|
||||
|
||||
// Note that the object mask is closely linked to the texture/effect
|
||||
// so we index based on the texture index,
|
||||
unsigned int i = triangleBin.getTextureIndex() % _status.size();
|
||||
unsigned int i = texIndex % _status.size();
|
||||
if (i < _masks.size()) {
|
||||
return _masks[i].get();
|
||||
} else {
|
||||
|
||||
@@ -119,13 +119,13 @@ public:
|
||||
/**
|
||||
* Get the textured state.
|
||||
*/
|
||||
simgear::Effect* get_effect(const SGTexturedTriangleBin& triangleBin);
|
||||
simgear::Effect* get_one_effect(int texIndex);
|
||||
simgear::Effect* get_effect();
|
||||
|
||||
/**
|
||||
* Get the textured state.
|
||||
*/
|
||||
osg::Texture2D* get_object_mask(const SGTexturedTriangleBin& triangleBin);
|
||||
osg::Texture2D* get_one_object_mask(int texIndex);
|
||||
|
||||
|
||||
/**
|
||||
@@ -273,6 +273,14 @@ public:
|
||||
* @return the texture to use for trees.
|
||||
*/
|
||||
inline std::string get_tree_texture () const { return tree_texture; }
|
||||
|
||||
|
||||
/**
|
||||
* Get the effect file name to use for trees
|
||||
*
|
||||
* @return the effect to use for this set of trees.
|
||||
*/
|
||||
inline std::string get_tree_effect () const { return tree_effect; }
|
||||
|
||||
/**
|
||||
* Get the cosine of the maximum tree density slope angle. We
|
||||
@@ -476,6 +484,9 @@ private:
|
||||
|
||||
// Tree texture, typically a strip of applicable tree textures
|
||||
std::string tree_texture;
|
||||
|
||||
// Tree effect to be used for a particular material
|
||||
std::string tree_effect;
|
||||
|
||||
// Object mask, a simple RGB texture used as a mask when placing
|
||||
// random vegetation, objects and buildings
|
||||
|
||||
@@ -127,8 +127,12 @@ void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
|
||||
|
||||
sortData.frameSorted = frameNumber;
|
||||
}
|
||||
|
||||
|
||||
#if OSG_VERSION_LESS_THAN(3,3,4)
|
||||
const Extensions* extensions = getExtensions(state.getContextID(),true);
|
||||
#else
|
||||
const GLExtensions* extensions = GLExtensions::Get(state.getContextID(), true);
|
||||
#endif
|
||||
GLfloat ua1[3] = { (GLfloat) alpha_factor,
|
||||
(GLfloat) shade_factor,
|
||||
(GLfloat) cloud_height };
|
||||
|
||||
@@ -8,9 +8,12 @@ set(HEADERS
|
||||
SGDirectionalLightBin.hxx
|
||||
SGLightBin.hxx
|
||||
SGModelBin.hxx
|
||||
SGNodeTriangles.hxx
|
||||
SGOceanTile.hxx
|
||||
SGReaderWriterBTG.hxx
|
||||
SGTexturedTriangleBin.hxx
|
||||
SGTileDetailsCallback.hxx
|
||||
SGTileGeometryBin.hxx
|
||||
SGTriangleBin.hxx
|
||||
SGVasiDrawable.hxx
|
||||
SGVertexArrayBin.hxx
|
||||
|
||||
@@ -386,10 +386,10 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
|
||||
int row = ((int) (mt_rand(&seed) * 1000)) % 5;
|
||||
float base_y = (float) row * 16.0 * 3.0 / 1024.0;
|
||||
float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
|
||||
float left_x = 32.0 / 1024.0 * round((float) building.width / 6.0f);
|
||||
float left_x = 32.0 / 1024.0 * SGMisc<double>::round((float)building.width / 6.0f);
|
||||
float right_x = 0.0f;
|
||||
float front_x = 384.0/1024.0;
|
||||
float back_x = 384.0/1024.0 + 32.0 / 1024.0 * round((float) building.depth/ 6.0f);
|
||||
float back_x = 384.0 / 1024.0 + 32.0 / 1024.0 * SGMisc<double>::round((float)building.depth / 6.0f);
|
||||
|
||||
// BASEMENT - uses the baseline texture
|
||||
for (unsigned int i = 0; i < 16; i++) {
|
||||
@@ -424,7 +424,7 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
|
||||
if (building.pitched) {
|
||||
// Use the entire height of the roof texture
|
||||
top_y = base_y + 16.0 * 3.0 / 1024.0;
|
||||
left_x = 512/1024.0 + 32.0 / 1024.0 * round(building.width / 6.0f);
|
||||
left_x = 512 / 1024.0 + 32.0 / 1024.0 * SGMisc<double>::round(building.width / 6.0f);
|
||||
right_x = 512/1024.0;
|
||||
front_x = 480.0/1024.0;
|
||||
back_x = 512.0/1024.0;
|
||||
@@ -475,7 +475,7 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
|
||||
int column = ((int) (mt_rand(&seed) * 1000)) % 5;
|
||||
float base_y = 288 / 1024.0;
|
||||
float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
|
||||
float left_x = column * 192.0 /1024.0 + 32.0 / 1024.0 * round((float) building.width / 10.0f);
|
||||
float left_x = column * 192.0 / 1024.0 + 32.0 / 1024.0 * SGMisc<double>::round((float)building.width / 10.0f);
|
||||
float right_x = column * 192.0 /1024.0;
|
||||
|
||||
// BASEMENT - uses the baseline texture
|
||||
@@ -560,7 +560,7 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
|
||||
int column = ((int) (mt_rand(&seed) * 1000)) % 8;
|
||||
float base_y = 576 / 1024.0;
|
||||
float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
|
||||
float left_x = column * 128.0 /1024.0 + 32.0 / 1024.0 * round((float) building.width / 20.0f);
|
||||
float left_x = column * 128.0 / 1024.0 + 32.0 / 1024.0 * SGMisc<double>::round((float)building.width / 20.0f);
|
||||
float right_x = column * 128.0 /1024.0;
|
||||
|
||||
// BASEMENT - uses the baseline texture
|
||||
|
||||
485
simgear/scene/tgdb/SGNodeTriangles.hxx
Normal file
485
simgear/scene/tgdb/SGNodeTriangles.hxx
Normal file
@@ -0,0 +1,485 @@
|
||||
// future API - just run through once to convert from OSG to SG
|
||||
// then we can use these triangle lists for random
|
||||
// trees/lights/buildings/objects
|
||||
struct SGTexturedTriangle
|
||||
{
|
||||
public:
|
||||
std::vector<SGVec3f> vertices;
|
||||
std::vector<SGVec2f> texcoords;
|
||||
};
|
||||
|
||||
struct SGBorderContour
|
||||
{
|
||||
public:
|
||||
SGVec3d start;
|
||||
SGVec3d end;
|
||||
};
|
||||
|
||||
class SGTriangleInfo
|
||||
{
|
||||
public:
|
||||
SGTriangleInfo( const SGVec3d& center ) {
|
||||
gbs_center = center;
|
||||
mt_init(&seed, 123);
|
||||
}
|
||||
|
||||
// API used to build the Info by the visitor
|
||||
void addGeometry( osg::Geometry* g ) {
|
||||
geometries.push_back(g);
|
||||
}
|
||||
|
||||
void setMaterial( SGMaterial* m ) {
|
||||
mat = m;
|
||||
}
|
||||
|
||||
SGMaterial* getMaterial( void ) const {
|
||||
return mat;
|
||||
}
|
||||
|
||||
// API used to get a specific texture or effect from a material. Materials can have
|
||||
// multiple textures - use the floor of the x coordinate of the first vertes to select it.
|
||||
// This will be constant, and give the same result each time to select one effect/texture per drawable.
|
||||
int getTextureIndex( void ) const {
|
||||
int texInfo = 0;
|
||||
const osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
|
||||
if ( vertices ) {
|
||||
const osg::Vec3 *v0 = &vertices->operator[](0);
|
||||
texInfo = floor(v0->x());
|
||||
}
|
||||
return texInfo;
|
||||
}
|
||||
|
||||
// new API - TODO
|
||||
void getTriangles( std::vector<SGTexturedTriangle>& tris )
|
||||
{
|
||||
const osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
|
||||
const osg::Vec2Array* texcoords = dynamic_cast<osg::Vec2Array*>(geometries[0]->getTexCoordArray(0));
|
||||
|
||||
int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
|
||||
if ( numPrimitiveSets > 0 ) {
|
||||
const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
|
||||
unsigned int numIndices = ps->getNumIndices();
|
||||
|
||||
for ( unsigned int i=2; i<numIndices; i+= 3 ) {
|
||||
SGTexturedTriangle tri;
|
||||
|
||||
tri.vertices.push_back( toSG(vertices->operator[](ps->index(i-2))) );
|
||||
tri.vertices.push_back( toSG(vertices->operator[](ps->index(i-1))) );
|
||||
tri.vertices.push_back( toSG(vertices->operator[](ps->index(i-0))) );
|
||||
|
||||
tri.texcoords.push_back( toSG(texcoords->operator[](ps->index(i-2))) );
|
||||
tri.texcoords.push_back( toSG(texcoords->operator[](ps->index(i-1))) );
|
||||
tri.texcoords.push_back( toSG(texcoords->operator[](ps->index(i-0))) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getBorderContours( std::vector<SGBorderContour>& border )
|
||||
{
|
||||
// each structure contains a list of target indexes and a count
|
||||
int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
|
||||
if ( numPrimitiveSets > 0 ) {
|
||||
const osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
|
||||
|
||||
const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
|
||||
unsigned int numTriangles = ps->getNumIndices()/3;
|
||||
|
||||
// use a map for fast lookup map the segment as a 64 bit int
|
||||
std::map<uint64_t, int> segCounter;
|
||||
uint32_t idx1, idx2;
|
||||
uint64_t key;
|
||||
|
||||
for ( unsigned int i=0; i<numTriangles; i+= 3 ) {
|
||||
// first seg
|
||||
if ( ps->index(i+0) < ps->index(i+1) ) {
|
||||
idx1 = ps->index(i+0);
|
||||
idx2 = ps->index(i+1);
|
||||
} else {
|
||||
idx1 = ps->index(i+1);
|
||||
idx2 = ps->index(i+0);
|
||||
}
|
||||
|
||||
key=( (uint64_t)idx1<<32) | (uint64_t)idx2;
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "key " << std::hex << key << std::dec << " count is " << segCounter[key] );
|
||||
segCounter[key]++;
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "after increment key " << std::hex << key << std::dec << " count is " << segCounter[key] );
|
||||
|
||||
// second seg
|
||||
if ( ps->index(i+1) < ps->index(i+2) ) {
|
||||
idx1 = ps->index(i+1);
|
||||
idx2 = ps->index(i+2);
|
||||
} else {
|
||||
idx1 = ps->index(i+2);
|
||||
idx2 = ps->index(i+1);
|
||||
}
|
||||
|
||||
key=( (uint64_t)idx1<<32) | (uint64_t)idx2;
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "key " << std::hex << key << std::dec << " count is " << segCounter[key] );
|
||||
segCounter[key]++;
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "after increment key " << std::hex << key << std::dec << " count is " << segCounter[key] );
|
||||
|
||||
// third seg
|
||||
if ( ps->index(i+2) < ps->index(i+0) ) {
|
||||
idx1 = ps->index(i+2);
|
||||
idx2 = ps->index(i+0);
|
||||
} else {
|
||||
idx1 = ps->index(i+0);
|
||||
idx2 = ps->index(i+2);
|
||||
}
|
||||
|
||||
key=( (uint64_t)idx1<<32) | (uint64_t)idx2;
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "key " << std::hex << key << std::dec << " count is " << segCounter[key] );
|
||||
segCounter[key]++;
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "after increment key " << std::hex << key << std::dec << " count is " << segCounter[key] );
|
||||
}
|
||||
|
||||
// return all segments with count = 1 ( border )
|
||||
std::map<uint64_t, int>::iterator segIt = segCounter.begin();
|
||||
while ( segIt != segCounter.end() ) {
|
||||
if ( segIt->second == 1 ) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "key " << std::hex << segIt->first << std::dec << " count is " << segIt->second );
|
||||
|
||||
unsigned int iStart = segIt->first >> 32;
|
||||
unsigned int iEnd = segIt->first & 0x00000000FFFFFFFF;
|
||||
|
||||
SGBorderContour bc;
|
||||
|
||||
bc.start = toVec3d(toSG(vertices->operator[](iStart)));
|
||||
bc.end = toVec3d(toSG(vertices->operator[](iEnd)));
|
||||
border.push_back( bc );
|
||||
}
|
||||
segIt++;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// debug out - requires GDAL
|
||||
//
|
||||
//
|
||||
//
|
||||
SGGeod geodPos = SGGeod::fromCart(gbs_center);
|
||||
SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180);
|
||||
|
||||
for ( unsigned int i=0; i<border.size(); i++ ){
|
||||
// de-rotate and translate : todo - create a paralell vertex list so we just do this
|
||||
// once per vertex, not for every triangle's use of the vertex
|
||||
SGVec3d sgVStart = hlOr.backTransform( border[i].start) + gbs_center;
|
||||
SGVec3d sgVEnd = hlOr.backTransform( border[i].end) + gbs_center;
|
||||
|
||||
// convert from cartesian to Geodetic, and save as a list of Geods for output
|
||||
SGGeod gStart = SGGeod::fromCart(sgVStart);
|
||||
SGGeod gEnd = SGGeod::fromCart(sgVEnd);
|
||||
|
||||
SGShapefile::FromSegment( gStart, gEnd, true, "./borders", mat->get_names()[0], "border" );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Random buildings API - get num triangles, then get a triangle at index
|
||||
unsigned int getNumTriangles( void ) const {
|
||||
unsigned int num_triangles = 0;
|
||||
|
||||
if ( !geometries.empty() ) {
|
||||
int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
|
||||
if ( numPrimitiveSets > 0 ) {
|
||||
const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
|
||||
unsigned int numIndices = ps->getNumIndices();
|
||||
num_triangles = numIndices/3;
|
||||
}
|
||||
}
|
||||
|
||||
return num_triangles;
|
||||
}
|
||||
|
||||
void getTriangle(unsigned int i, std::vector<SGVec3f>& triVerts, std::vector<SGVec2f>& triTCs) const {
|
||||
const osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
|
||||
const osg::Vec2Array* texcoords = dynamic_cast<osg::Vec2Array*>(geometries[0]->getTexCoordArray(0));
|
||||
|
||||
if ( !geometries.empty() ) {
|
||||
int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
|
||||
if ( numPrimitiveSets > 0 ) {
|
||||
const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
|
||||
int idxStart = i*3;
|
||||
|
||||
triVerts.push_back( toSG(vertices->operator[](ps->index(idxStart+0))) );
|
||||
triVerts.push_back( toSG(vertices->operator[](ps->index(idxStart+1))) );
|
||||
triVerts.push_back( toSG(vertices->operator[](ps->index(idxStart+2))) );
|
||||
|
||||
triTCs.push_back( toSG(texcoords->operator[](ps->index(idxStart+0))) );
|
||||
triTCs.push_back( toSG(texcoords->operator[](ps->index(idxStart+1))) );
|
||||
triTCs.push_back( toSG(texcoords->operator[](ps->index(idxStart+2))) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// random lights and trees - just get a list of points on where to add the light / tree
|
||||
// TODO move this out - and handle in the random light / tree code
|
||||
// just use generic triangle API.
|
||||
void addRandomSurfacePoints(float coverage, float offset,
|
||||
osg::Texture2D* object_mask,
|
||||
std::vector<SGVec3f>& points)
|
||||
{
|
||||
if ( !geometries.empty() ) {
|
||||
const osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
|
||||
const osg::Vec2Array* texcoords = dynamic_cast<osg::Vec2Array*>(geometries[0]->getTexCoordArray(0));
|
||||
|
||||
int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
|
||||
if ( numPrimitiveSets > 0 ) {
|
||||
const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
|
||||
unsigned int numIndices = ps->getNumIndices();
|
||||
|
||||
for ( unsigned int i=2; i<numIndices; i+= 3 ) {
|
||||
SGVec3f v0 = toSG(vertices->operator[](ps->index(i-2)));
|
||||
SGVec3f v1 = toSG(vertices->operator[](ps->index(i-1)));
|
||||
SGVec3f v2 = toSG(vertices->operator[](ps->index(i-0)));
|
||||
|
||||
SGVec2f t0 = toSG(texcoords->operator[](ps->index(i-2)));
|
||||
SGVec2f t1 = toSG(texcoords->operator[](ps->index(i-1)));
|
||||
SGVec2f t2 = toSG(texcoords->operator[](ps->index(i-0)));
|
||||
|
||||
SGVec3f normal = cross(v1 - v0, v2 - v0);
|
||||
|
||||
// Compute the area
|
||||
float area = 0.5f*length(normal);
|
||||
if (area <= SGLimitsf::min())
|
||||
continue;
|
||||
|
||||
// For partial units of area, use a zombie door method to
|
||||
// create the proper random chance of a light being created
|
||||
// for this triangle
|
||||
float unit = area + mt_rand(&seed)*coverage;
|
||||
|
||||
SGVec3f offsetVector = offset*normalize(normal);
|
||||
// generate a light point for each unit of area
|
||||
|
||||
while ( coverage < unit ) {
|
||||
float a = mt_rand(&seed);
|
||||
float b = mt_rand(&seed);
|
||||
|
||||
if ( a + b > 1 ) {
|
||||
a = 1 - a;
|
||||
b = 1 - b;
|
||||
}
|
||||
float c = 1 - a - b;
|
||||
SGVec3f randomPoint = offsetVector + a*v0 + b*v1 + c*v2;
|
||||
|
||||
if (object_mask != NULL) {
|
||||
SGVec2f texCoord = a*t0 + b*t1 + c*t2;
|
||||
|
||||
// Check this random point against the object mask
|
||||
// red channel.
|
||||
osg::Image* img = object_mask->getImage();
|
||||
unsigned int x = (int) (img->s() * texCoord.x()) % img->s();
|
||||
unsigned int y = (int) (img->t() * texCoord.y()) % img->t();
|
||||
|
||||
if (mt_rand(&seed) < img->getColor(x, y).r()) {
|
||||
points.push_back(randomPoint);
|
||||
}
|
||||
} else {
|
||||
// No object mask, so simply place the object
|
||||
points.push_back(randomPoint);
|
||||
}
|
||||
unit -= coverage;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addRandomTreePoints(float wood_coverage,
|
||||
osg::Texture2D* object_mask,
|
||||
float vegetation_density,
|
||||
float cos_max_density_angle,
|
||||
float cos_zero_density_angle,
|
||||
std::vector<SGVec3f>& points,
|
||||
std::vector<SGVec3f>& normals)
|
||||
{
|
||||
if ( !geometries.empty() ) {
|
||||
const osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
|
||||
const osg::Vec2Array* texcoords = dynamic_cast<osg::Vec2Array*>(geometries[0]->getTexCoordArray(0));
|
||||
|
||||
int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
|
||||
if ( numPrimitiveSets > 0 ) {
|
||||
const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
|
||||
unsigned int numIndices = ps->getNumIndices();
|
||||
|
||||
for ( unsigned int i=2; i<numIndices; i+= 3 ) {
|
||||
SGVec3f v0 = toSG(vertices->operator[](ps->index(i-2)));
|
||||
SGVec3f v1 = toSG(vertices->operator[](ps->index(i-1)));
|
||||
SGVec3f v2 = toSG(vertices->operator[](ps->index(i-0)));
|
||||
|
||||
SGVec2f t0 = toSG(texcoords->operator[](ps->index(i-2)));
|
||||
SGVec2f t1 = toSG(texcoords->operator[](ps->index(i-1)));
|
||||
SGVec2f t2 = toSG(texcoords->operator[](ps->index(i-0)));
|
||||
|
||||
SGVec3f normal = cross(v1 - v0, v2 - v0);
|
||||
|
||||
// Ensure the slope isn't too steep by checking the
|
||||
// cos of the angle between the slope normal and the
|
||||
// vertical (conveniently the z-component of the normalized
|
||||
// normal) and values passed in.
|
||||
float alpha = normalize(normal).z();
|
||||
float slope_density = 1.0;
|
||||
|
||||
if (alpha < cos_zero_density_angle)
|
||||
continue; // Too steep for any vegetation
|
||||
|
||||
if (alpha < cos_max_density_angle) {
|
||||
slope_density =
|
||||
(alpha - cos_zero_density_angle) / (cos_max_density_angle - cos_zero_density_angle);
|
||||
}
|
||||
|
||||
// Compute the area
|
||||
float area = 0.5f*length(normal);
|
||||
if (area <= SGLimitsf::min())
|
||||
continue;
|
||||
|
||||
// Determine the number of trees, taking into account vegetation
|
||||
// density (which is linear) and the slope density factor.
|
||||
// Use a zombie door method to create the proper random chance
|
||||
// of a tree being created for partial values.
|
||||
int woodcount = (int) (vegetation_density * vegetation_density *
|
||||
slope_density *
|
||||
area / wood_coverage + mt_rand(&seed));
|
||||
|
||||
for (int j = 0; j < woodcount; j++) {
|
||||
float a = mt_rand(&seed);
|
||||
float b = mt_rand(&seed);
|
||||
|
||||
if ( a + b > 1.0f ) {
|
||||
a = 1.0f - a;
|
||||
b = 1.0f - b;
|
||||
}
|
||||
|
||||
float c = 1.0f - a - b;
|
||||
|
||||
SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
|
||||
|
||||
if (object_mask != NULL) {
|
||||
SGVec2f texCoord = a*t0 + b*t1 + c*t2;
|
||||
|
||||
// Check this random point against the object mask
|
||||
// green (for trees) channel.
|
||||
osg::Image* img = object_mask->getImage();
|
||||
unsigned int x = (int) (img->s() * texCoord.x()) % img->s();
|
||||
unsigned int y = (int) (img->t() * texCoord.y()) % img->t();
|
||||
|
||||
if (mt_rand(&seed) < img->getColor(x, y).g()) {
|
||||
// The red channel contains the rotation for this object
|
||||
points.push_back(randomPoint);
|
||||
normals.push_back(normalize(normal));
|
||||
}
|
||||
} else {
|
||||
points.push_back(randomPoint);
|
||||
normals.push_back(normalize(normal));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// debug : this will save the tile as a shapefile that can be viewed in QGIS.
|
||||
// NOTE: this is really slow....
|
||||
// remember - we need to de-rotate the tile, then translate back to gbs_center.
|
||||
void dumpBorder() {
|
||||
//dump the first triangle only of the first geometry, for now...
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "effect geode has " << geometries.size() << " geometries" );
|
||||
|
||||
const osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometries[0]->getVertexArray());
|
||||
if ( vertices ) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, " geometry has " << vertices->getNumElements() << " vertices" );
|
||||
}
|
||||
|
||||
if ( !geometries.empty() ) {
|
||||
int numPrimitiveSets = geometries[0]->getNumPrimitiveSets();
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, " geometry has " << numPrimitiveSets << " primitive sets" );
|
||||
|
||||
if ( numPrimitiveSets > 0 ) {
|
||||
const osg::PrimitiveSet* ps = geometries[0]->getPrimitiveSet(0);
|
||||
unsigned int numIndices = ps->getNumIndices();
|
||||
|
||||
// create the same quat we used to rotate here
|
||||
// - use backTransform to go back to original node location
|
||||
SGGeod geodPos = SGGeod::fromCart(gbs_center);
|
||||
SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180);
|
||||
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, " primitive set has has " << numIndices << " indices" );
|
||||
for ( unsigned int i=2; i<numIndices; i+= 3 ) {
|
||||
if ( numIndices >= 3 ) {
|
||||
unsigned int v0i = ps->index(i-2);
|
||||
unsigned int v1i = ps->index(i-1);
|
||||
unsigned int v2i = ps->index(i-0);
|
||||
|
||||
const osg::Vec3 *v0 = &vertices->operator[](v0i);
|
||||
const osg::Vec3 *v1 = &vertices->operator[](v1i);
|
||||
const osg::Vec3 *v2 = &vertices->operator[](v2i);
|
||||
|
||||
// de-rotate and translate : todo - create a paralell vertex list so we just do this
|
||||
// once per vertex, not for every triangle's use of the vertex
|
||||
SGVec3d vec0 = hlOr.backTransform( toVec3d(toSG(*v0))) + gbs_center;
|
||||
SGVec3d vec1 = hlOr.backTransform( toVec3d(toSG(*v1))) + gbs_center;
|
||||
SGVec3d vec2 = hlOr.backTransform( toVec3d(toSG(*v2))) + gbs_center;
|
||||
|
||||
// convert from cartesian to Geodetic, and save as a list of Geods for output
|
||||
std::vector<SGGeod> triangle;
|
||||
triangle.push_back( SGGeod::fromCart(vec0) );
|
||||
triangle.push_back( SGGeod::fromCart(vec1) );
|
||||
triangle.push_back( SGGeod::fromCart(vec2) );
|
||||
|
||||
SGShapefile::FromGeodList( triangle, true, "./triangles", mat->get_names()[0], "tri" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
mt seed;
|
||||
SGMaterial* mat;
|
||||
SGVec3d gbs_center;
|
||||
std::vector<osg::Geometry*> geometries;
|
||||
std::vector<int> polygon_border; // TODO
|
||||
};
|
||||
|
||||
// This visitor will generate an SGTriangleInfo.
|
||||
// currently, it looks like it could save multiple lists, which could be the case
|
||||
// if multiple osg::geods are found with osg::Geometry.
|
||||
// But right now, we store a single PrimitiveSet under a single EffectGeod.
|
||||
// so the traversal should only find a single EffectGeod - building a single SGTriangleInfo
|
||||
class GetNodeTriangles : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
GetNodeTriangles(const SGVec3d& c, std::vector<SGTriangleInfo>* nt) : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ), center(c), nodeTris(nt) {}
|
||||
|
||||
// This method gets called for every node in the scene
|
||||
// graph. Check each node to see if it has user
|
||||
// out target. If so, save the node's address.
|
||||
virtual void apply( osg::Node& node )
|
||||
{
|
||||
EffectGeode* eg = dynamic_cast<EffectGeode*>(&node);
|
||||
if ( eg ) {
|
||||
// get the material from the user info
|
||||
SGTriangleInfo triInfo( center );
|
||||
triInfo.setMaterial( eg->getMaterial() );
|
||||
|
||||
// let's find the drawables for this node
|
||||
int numDrawables = eg->getNumDrawables();
|
||||
for ( int i=0; i<numDrawables; i++ ) {
|
||||
triInfo.addGeometry( eg->getDrawable(i)->asGeometry() );
|
||||
}
|
||||
|
||||
nodeTris->push_back( triInfo );
|
||||
}
|
||||
|
||||
// Keep traversing the rest of the scene graph.
|
||||
traverse( node );
|
||||
}
|
||||
|
||||
protected:
|
||||
SGVec3d center;
|
||||
std::vector<SGTriangleInfo>* nodeTris;
|
||||
};
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <osg/Geometry>
|
||||
#include <osg/PrimitiveSet>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/ref_ptr>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <simgear/math/sg_random.h>
|
||||
@@ -122,16 +123,16 @@ public:
|
||||
osg::DrawElements* getDrawElements()
|
||||
{
|
||||
if (count > 65535) {
|
||||
free (_ushortElements);
|
||||
_ushortElements = 0;
|
||||
return _uintElements;
|
||||
} else {
|
||||
free (_uintElements);
|
||||
_uintElements = 0;
|
||||
return _ushortElements;
|
||||
}
|
||||
}
|
||||
protected:
|
||||
osg::DrawElementsUShort* _ushortElements;
|
||||
osg::DrawElementsUInt* _uintElements;
|
||||
osg::ref_ptr<osg::DrawElementsUShort> _ushortElements;
|
||||
osg::ref_ptr<osg::DrawElementsUInt> _uintElements;
|
||||
unsigned count;
|
||||
};
|
||||
|
||||
@@ -215,7 +216,8 @@ public:
|
||||
float vegetation_density,
|
||||
float cos_max_density_angle,
|
||||
float cos_zero_density_angle,
|
||||
std::vector<SGVec3f>& points)
|
||||
std::vector<SGVec3f>& points,
|
||||
std::vector<SGVec3f>& normals)
|
||||
{
|
||||
unsigned num = getNumTriangles();
|
||||
for (unsigned i = 0; i < num; ++i) {
|
||||
@@ -281,9 +283,11 @@ public:
|
||||
if (mt_rand(&seed) < img->getColor(x, y).g()) {
|
||||
// The red channel contains the rotation for this object
|
||||
points.push_back(randomPoint);
|
||||
normals.push_back(normalize(normal));
|
||||
}
|
||||
} else {
|
||||
points.push_back(randomPoint);
|
||||
normals.push_back(normalize(normal));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1146
simgear/scene/tgdb/SGTileDetailsCallback.hxx
Normal file
1146
simgear/scene/tgdb/SGTileDetailsCallback.hxx
Normal file
File diff suppressed because it is too large
Load Diff
304
simgear/scene/tgdb/SGTileGeometryBin.hxx
Normal file
304
simgear/scene/tgdb/SGTileGeometryBin.hxx
Normal file
@@ -0,0 +1,304 @@
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include "obj.hxx"
|
||||
|
||||
#include <simgear/scene/material/EffectGeode.hxx>
|
||||
#include <simgear/scene/material/matlib.hxx>
|
||||
#include <simgear/scene/material/mat.hxx>
|
||||
|
||||
#include "SGTexturedTriangleBin.hxx"
|
||||
|
||||
using namespace simgear;
|
||||
|
||||
typedef std::map<std::string,SGTexturedTriangleBin> SGMaterialTriangleMap;
|
||||
|
||||
// Class handling the initial BTG loading : should probably be in its own file
|
||||
// it is very closely coupled with SGTexturedTriangleBin.hxx
|
||||
// it was used to load fans, strips, and triangles.
|
||||
// WS2.0 no longer uses fans or strips, but people still use ws1.0, so we need
|
||||
// to keep this functionality.
|
||||
class SGTileGeometryBin : public osg::Referenced {
|
||||
public:
|
||||
SGMaterialTriangleMap materialTriangleMap;
|
||||
|
||||
SGTileGeometryBin() {}
|
||||
|
||||
static SGVec2f
|
||||
getTexCoord(const std::vector<SGVec2f>& texCoords, const int_list& tc,
|
||||
const SGVec2f& tcScale, unsigned i)
|
||||
{
|
||||
if (tc.empty())
|
||||
return tcScale;
|
||||
else if (tc.size() == 1)
|
||||
return mult(texCoords[tc[0]], tcScale);
|
||||
else
|
||||
return mult(texCoords[tc[i]], tcScale);
|
||||
}
|
||||
|
||||
SGVec2f getTexCoordScale(const std::string& name, SGMaterialCache* matcache)
|
||||
{
|
||||
if (!matcache)
|
||||
return SGVec2f(1, 1);
|
||||
SGMaterial* material = matcache->find(name);
|
||||
if (!material)
|
||||
return SGVec2f(1, 1);
|
||||
|
||||
return material->get_tex_coord_scale();
|
||||
}
|
||||
|
||||
static void
|
||||
addTriangleGeometry(SGTexturedTriangleBin& triangles,
|
||||
const SGBinObject& obj, unsigned grp,
|
||||
const SGVec2f& tc0Scale,
|
||||
const SGVec2f& tc1Scale)
|
||||
{
|
||||
const std::vector<SGVec3d>& vertices(obj.get_wgs84_nodes());
|
||||
const std::vector<SGVec3f>& normals(obj.get_normals());
|
||||
const std::vector<SGVec2f>& texCoords(obj.get_texcoords());
|
||||
const int_list& tris_v(obj.get_tris_v()[grp]);
|
||||
const int_list& tris_n(obj.get_tris_n()[grp]);
|
||||
const tci_list& tris_tc(obj.get_tris_tcs()[grp]);
|
||||
bool num_norms_is_num_verts = true;
|
||||
|
||||
if (tris_v.size() != tris_n.size()) {
|
||||
// If the normal indices do not match, they should be inmplicitly
|
||||
// the same than the vertex indices.
|
||||
num_norms_is_num_verts = false;
|
||||
}
|
||||
|
||||
if ( !tris_tc[1].empty() ) {
|
||||
triangles.hasSecondaryTexCoord(true);
|
||||
}
|
||||
|
||||
for (unsigned i = 2; i < tris_v.size(); i += 3) {
|
||||
SGVertNormTex v0;
|
||||
v0.SetVertex( toVec3f(vertices[tris_v[i-2]]) );
|
||||
v0.SetNormal( num_norms_is_num_verts ? normals[tris_n[i-2]] :
|
||||
normals[tris_v[i-2]] );
|
||||
v0.SetTexCoord( 0, getTexCoord(texCoords, tris_tc[0], tc0Scale, i-2) );
|
||||
if (!tris_tc[1].empty()) {
|
||||
v0.SetTexCoord( 1, getTexCoord(texCoords, tris_tc[1], tc1Scale, i-2) );
|
||||
}
|
||||
SGVertNormTex v1;
|
||||
v1.SetVertex( toVec3f(vertices[tris_v[i-1]]) );
|
||||
v1.SetNormal( num_norms_is_num_verts ? normals[tris_n[i-1]] :
|
||||
normals[tris_v[i-1]] );
|
||||
v1.SetTexCoord( 0, getTexCoord(texCoords, tris_tc[0], tc0Scale, i-1) );
|
||||
if (!tris_tc[1].empty()) {
|
||||
v1.SetTexCoord( 1, getTexCoord(texCoords, tris_tc[1], tc1Scale, i-1) );
|
||||
}
|
||||
SGVertNormTex v2;
|
||||
v2.SetVertex( toVec3f(vertices[tris_v[i]]) );
|
||||
v2.SetNormal( num_norms_is_num_verts ? normals[tris_n[i]] :
|
||||
normals[tris_v[i]] );
|
||||
v2.SetTexCoord( 0, getTexCoord(texCoords, tris_tc[0], tc0Scale, i) );
|
||||
if (!tris_tc[1].empty()) {
|
||||
v2.SetTexCoord( 1, getTexCoord(texCoords, tris_tc[1], tc1Scale, i) );
|
||||
}
|
||||
|
||||
triangles.insert(v0, v1, v2);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
addStripGeometry(SGTexturedTriangleBin& triangles,
|
||||
const SGBinObject& obj, unsigned grp,
|
||||
const SGVec2f& tc0Scale,
|
||||
const SGVec2f& tc1Scale)
|
||||
{
|
||||
const std::vector<SGVec3d>& vertices(obj.get_wgs84_nodes());
|
||||
const std::vector<SGVec3f>& normals(obj.get_normals());
|
||||
const std::vector<SGVec2f>& texCoords(obj.get_texcoords());
|
||||
const int_list& strips_v(obj.get_strips_v()[grp]);
|
||||
const int_list& strips_n(obj.get_strips_n()[grp]);
|
||||
const tci_list& strips_tc(obj.get_strips_tcs()[grp]);
|
||||
bool num_norms_is_num_verts = true;
|
||||
|
||||
if (strips_v.size() != strips_n.size()) {
|
||||
// If the normal indices do not match, they should be inmplicitly
|
||||
// the same than the vertex indices.
|
||||
num_norms_is_num_verts = false;
|
||||
}
|
||||
|
||||
if ( !strips_tc[1].empty() ) {
|
||||
triangles.hasSecondaryTexCoord(true);
|
||||
}
|
||||
|
||||
for (unsigned i = 2; i < strips_v.size(); ++i) {
|
||||
SGVertNormTex v0;
|
||||
v0.SetVertex( toVec3f(vertices[strips_v[i-2]]) );
|
||||
v0.SetNormal( num_norms_is_num_verts ? normals[strips_n[i-2]] :
|
||||
normals[strips_v[i-2]] );
|
||||
v0.SetTexCoord( 0, getTexCoord(texCoords, strips_tc[0], tc0Scale, i-2) );
|
||||
if (!strips_tc[1].empty()) {
|
||||
v0.SetTexCoord( 1, getTexCoord(texCoords, strips_tc[1], tc1Scale, i-2) );
|
||||
}
|
||||
SGVertNormTex v1;
|
||||
v1.SetVertex( toVec3f(vertices[strips_v[i-1]]) );
|
||||
v1.SetNormal( num_norms_is_num_verts ? normals[strips_n[i-1]] :
|
||||
normals[strips_v[i-1]] );
|
||||
v1.SetTexCoord( 0, getTexCoord(texCoords, strips_tc[1], tc0Scale, i-1) );
|
||||
if (!strips_tc[1].empty()) {
|
||||
v1.SetTexCoord( 1, getTexCoord(texCoords, strips_tc[1], tc1Scale, i-1) );
|
||||
}
|
||||
SGVertNormTex v2;
|
||||
v2.SetVertex( toVec3f(vertices[strips_v[i]]) );
|
||||
v2.SetNormal( num_norms_is_num_verts ? normals[strips_n[i]] :
|
||||
normals[strips_v[i]] );
|
||||
v2.SetTexCoord( 0, getTexCoord(texCoords, strips_tc[0], tc0Scale, i) );
|
||||
if (!strips_tc[1].empty()) {
|
||||
v2.SetTexCoord( 1, getTexCoord(texCoords, strips_tc[1], tc1Scale, i) );
|
||||
}
|
||||
if (i%2)
|
||||
triangles.insert(v1, v0, v2);
|
||||
else
|
||||
triangles.insert(v0, v1, v2);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
addFanGeometry(SGTexturedTriangleBin& triangles,
|
||||
const SGBinObject& obj, unsigned grp,
|
||||
const SGVec2f& tc0Scale,
|
||||
const SGVec2f& tc1Scale)
|
||||
{
|
||||
const std::vector<SGVec3d>& vertices(obj.get_wgs84_nodes());
|
||||
const std::vector<SGVec3f>& normals(obj.get_normals());
|
||||
const std::vector<SGVec2f>& texCoords(obj.get_texcoords());
|
||||
const int_list& fans_v(obj.get_fans_v()[grp]);
|
||||
const int_list& fans_n(obj.get_fans_n()[grp]);
|
||||
const tci_list& fans_tc(obj.get_fans_tcs()[grp]);
|
||||
bool num_norms_is_num_verts = true;
|
||||
|
||||
if (fans_v.size() != fans_n.size()) {
|
||||
// If the normal indices do not match, they should be inmplicitly
|
||||
// the same than the vertex indices.
|
||||
num_norms_is_num_verts = false;
|
||||
}
|
||||
|
||||
if ( !fans_tc[1].empty() ) {
|
||||
triangles.hasSecondaryTexCoord(true);
|
||||
}
|
||||
|
||||
SGVertNormTex v0;
|
||||
v0.SetVertex( toVec3f(vertices[fans_v[0]]) );
|
||||
v0.SetNormal( num_norms_is_num_verts ? normals[fans_n[0]] :
|
||||
normals[fans_v[0]] );
|
||||
v0.SetTexCoord( 0, getTexCoord(texCoords, fans_tc[0], tc0Scale, 0) );
|
||||
if (!fans_tc[1].empty()) {
|
||||
v0.SetTexCoord( 1, getTexCoord(texCoords, fans_tc[1], tc1Scale, 0) );
|
||||
}
|
||||
SGVertNormTex v1;
|
||||
v1.SetVertex( toVec3f(vertices[fans_v[1]]) );
|
||||
v1.SetNormal( num_norms_is_num_verts ? normals[fans_n[1]] :
|
||||
normals[fans_v[1]] );
|
||||
v1.SetTexCoord( 0, getTexCoord(texCoords, fans_tc[0], tc0Scale, 1) );
|
||||
if (!fans_tc[1].empty()) {
|
||||
v1.SetTexCoord( 1, getTexCoord(texCoords, fans_tc[1], tc1Scale, 1) );
|
||||
}
|
||||
for (unsigned i = 2; i < fans_v.size(); ++i) {
|
||||
SGVertNormTex v2;
|
||||
v2.SetVertex( toVec3f(vertices[fans_v[i]]) );
|
||||
v2.SetNormal( num_norms_is_num_verts ? normals[fans_n[i]] :
|
||||
normals[fans_v[i]] );
|
||||
v2.SetTexCoord( 0, getTexCoord(texCoords, fans_tc[0], tc0Scale, i) );
|
||||
if (!fans_tc[1].empty()) {
|
||||
v2.SetTexCoord( 1, getTexCoord(texCoords, fans_tc[1], tc1Scale, i) );
|
||||
}
|
||||
triangles.insert(v0, v1, v2);
|
||||
v1 = v2;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
insertSurfaceGeometry(const SGBinObject& obj, SGMaterialCache* matcache)
|
||||
{
|
||||
if (obj.get_tris_n().size() < obj.get_tris_v().size() ||
|
||||
obj.get_tris_tcs().size() < obj.get_tris_v().size()) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT,
|
||||
"Group list sizes for triangles do not match!");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned grp = 0; grp < obj.get_tris_v().size(); ++grp) {
|
||||
std::string materialName = obj.get_tri_materials()[grp];
|
||||
SGVec2f tc0Scale = getTexCoordScale(materialName, matcache);
|
||||
SGVec2f tc1Scale(1.0, 1.0);
|
||||
addTriangleGeometry(materialTriangleMap[materialName],
|
||||
obj, grp, tc0Scale, tc1Scale );
|
||||
}
|
||||
|
||||
if (obj.get_strips_n().size() < obj.get_strips_v().size() ||
|
||||
obj.get_strips_tcs().size() < obj.get_strips_v().size()) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT,
|
||||
"Group list sizes for strips do not match!");
|
||||
return false;
|
||||
}
|
||||
for (unsigned grp = 0; grp < obj.get_strips_v().size(); ++grp) {
|
||||
std::string materialName = obj.get_strip_materials()[grp];
|
||||
SGVec2f tc0Scale = getTexCoordScale(materialName, matcache);
|
||||
SGVec2f tc1Scale(1.0, 1.0);
|
||||
addStripGeometry(materialTriangleMap[materialName],
|
||||
obj, grp, tc0Scale, tc1Scale);
|
||||
}
|
||||
|
||||
if (obj.get_fans_n().size() < obj.get_fans_v().size() ||
|
||||
obj.get_fans_tcs().size() < obj.get_fans_v().size()) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT,
|
||||
"Group list sizes for fans do not match!");
|
||||
return false;
|
||||
}
|
||||
for (unsigned grp = 0; grp < obj.get_fans_v().size(); ++grp) {
|
||||
std::string materialName = obj.get_fan_materials()[grp];
|
||||
SGVec2f tc0Scale = getTexCoordScale(materialName, matcache);
|
||||
SGVec2f tc1Scale(1.0, 1.0);
|
||||
addFanGeometry(materialTriangleMap[materialName],
|
||||
obj, grp, tc0Scale, tc1Scale );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
osg::Node* getSurfaceGeometry(SGMaterialCache* matcache, bool useVBOs) const
|
||||
{
|
||||
if (materialTriangleMap.empty())
|
||||
return 0;
|
||||
|
||||
EffectGeode* eg = NULL;
|
||||
osg::Group* group = (materialTriangleMap.size() > 1 ? new osg::Group : NULL);
|
||||
if (group) {
|
||||
group->setName("surfaceGeometryGroup");
|
||||
}
|
||||
|
||||
//osg::Geode* geode = new osg::Geode;
|
||||
SGMaterialTriangleMap::const_iterator i;
|
||||
for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) {
|
||||
osg::Geometry* geometry = i->second.buildGeometry(useVBOs);
|
||||
SGMaterial *mat = NULL;
|
||||
if (matcache) {
|
||||
mat = matcache->find(i->first);
|
||||
}
|
||||
eg = new EffectGeode;
|
||||
eg->setName("EffectGeode");
|
||||
if (mat) {
|
||||
eg->setMaterial(mat);
|
||||
eg->setEffect(mat->get_one_effect(i->second.getTextureIndex()));
|
||||
} else {
|
||||
eg->setMaterial(NULL);
|
||||
}
|
||||
eg->addDrawable(geometry);
|
||||
eg->runGenerators(geometry); // Generate extra data needed by effect
|
||||
if (group) {
|
||||
group->addChild(eg);
|
||||
}
|
||||
}
|
||||
|
||||
if (group) {
|
||||
return group;
|
||||
} else {
|
||||
return eg;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -47,7 +47,11 @@ void ShaderGeometry::addObject(const Vec3& position, float scale,
|
||||
void ShaderGeometry::drawImplementation(osg::RenderInfo& renderInfo) const
|
||||
{
|
||||
State& state = *renderInfo.getState();
|
||||
#if OSG_VERSION_LESS_THAN(3,3,4)
|
||||
const Extensions* extensions = getExtensions(state.getContextID(), true);
|
||||
#else
|
||||
const GLExtensions* extensions = GLExtensions::Get(state.getContextID(), true);
|
||||
#endif
|
||||
Vec4Array::const_iterator citer = _posScaleArray->begin();
|
||||
Vec4Array::const_iterator cend = _posScaleArray->end();
|
||||
FloatArray::const_iterator viter = _vertexAttribArray->begin();
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include <simgear/scene/util/QuadTreeBuilder.hxx>
|
||||
#include <simgear/scene/util/RenderConstants.hxx>
|
||||
#include <simgear/scene/util/StateAttributeFactory.hxx>
|
||||
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
|
||||
#include <simgear/structure/OSGUtils.hxx>
|
||||
|
||||
#include "ShaderGeometry.hxx"
|
||||
@@ -62,6 +63,9 @@ using namespace osg;
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
bool use_tree_shadows;
|
||||
bool use_tree_normals;
|
||||
|
||||
// Tree instance scheme:
|
||||
// vertex - local position of quad vertex.
|
||||
// normal - x y scaling, z number of varieties
|
||||
@@ -164,15 +168,24 @@ Geometry* createTreeGeometry(float width, float height, int varieties)
|
||||
// Positions
|
||||
quadGeom->setColorArray(new Vec3Array);
|
||||
quadGeom->setColorBinding(Geometry::BIND_PER_VERTEX);
|
||||
FloatArray* rotation = new FloatArray(2);
|
||||
// Normals
|
||||
if (use_tree_shadows || use_tree_normals)
|
||||
{
|
||||
quadGeom->setSecondaryColorArray(new Vec3Array);
|
||||
quadGeom->setSecondaryColorBinding(Geometry::BIND_PER_VERTEX);
|
||||
}
|
||||
FloatArray* rotation = new FloatArray(3);
|
||||
(*rotation)[0] = 0.0;
|
||||
(*rotation)[1] = PI_2;
|
||||
if (use_tree_shadows) {(*rotation)[2] = -1.0;}
|
||||
quadGeom->setFogCoordArray(rotation);
|
||||
quadGeom->setFogCoordBinding(Geometry::BIND_PER_PRIMITIVE_SET);
|
||||
// The primitive sets render the same geometry, but the second
|
||||
// will rotated 90 degrees by the vertex shader, which uses the
|
||||
// fog coordinate as a rotation.
|
||||
for (int i = 0; i < 2; ++i)
|
||||
int imax = 2;
|
||||
if (use_tree_shadows) {imax = 3;}
|
||||
for (int i = 0; i < imax; ++i)
|
||||
quadGeom->addPrimitiveSet(new DrawArrays(PrimitiveSet::QUADS));
|
||||
return quadGeom;
|
||||
}
|
||||
@@ -184,13 +197,17 @@ EffectGeode* createTreeGeode(float width, float height, int varieties)
|
||||
return result;
|
||||
}
|
||||
|
||||
void addTreeToLeafGeode(Geode* geode, const SGVec3f& p)
|
||||
void addTreeToLeafGeode(Geode* geode, const SGVec3f& p, const SGVec3f& t)
|
||||
{
|
||||
Vec3 pos = toOsg(p);
|
||||
Vec3 ter = toOsg(t);
|
||||
unsigned int numDrawables = geode->getNumDrawables();
|
||||
Geometry* geom
|
||||
= static_cast<Geometry*>(geode->getDrawable(numDrawables - 1));
|
||||
Vec3Array* posArray = static_cast<Vec3Array*>(geom->getColorArray());
|
||||
Vec3Array* tnormalArray;
|
||||
if (use_tree_shadows || use_tree_normals)
|
||||
{tnormalArray = static_cast<Vec3Array*>(geom->getSecondaryColorArray());}
|
||||
if (posArray->size()
|
||||
>= static_cast<Vec3Array*>(geom->getVertexArray())->size()) {
|
||||
Vec3Array* paramsArray
|
||||
@@ -198,11 +215,17 @@ void addTreeToLeafGeode(Geode* geode, const SGVec3f& p)
|
||||
Vec3 params = (*paramsArray)[0];
|
||||
geom = createTreeGeometry(params.x(), params.y(), params.z());
|
||||
posArray = static_cast<Vec3Array*>(geom->getColorArray());
|
||||
if (use_tree_shadows || use_tree_normals)
|
||||
{tnormalArray = static_cast<Vec3Array*>(geom->getSecondaryColorArray());}
|
||||
geode->addDrawable(geom);
|
||||
}
|
||||
posArray->insert(posArray->end(), 4, pos);
|
||||
if (use_tree_shadows || use_tree_normals)
|
||||
{tnormalArray->insert(tnormalArray->end(),4,ter);}
|
||||
size_t numVerts = posArray->size();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
int imax = 2;
|
||||
if (use_tree_shadows) {imax = 3;}
|
||||
for (int i = 0; i < imax; ++i) {
|
||||
DrawArrays* primSet
|
||||
= static_cast<DrawArrays*>(geom->getPrimitiveSet(i));
|
||||
primSet->setCount(numVerts);
|
||||
@@ -218,14 +241,14 @@ namespace
|
||||
{
|
||||
struct MakeTreesLeaf
|
||||
{
|
||||
MakeTreesLeaf(float range, int varieties, float width, float height,
|
||||
MakeTreesLeaf(float range, int varieties, float width, float height,
|
||||
Effect* effect) :
|
||||
_range(range), _varieties(varieties),
|
||||
_width(width), _height(height), _effect(effect) {}
|
||||
|
||||
MakeTreesLeaf(const MakeTreesLeaf& rhs) :
|
||||
_range(rhs._range),
|
||||
_varieties(rhs._varieties), _width(rhs._width), _height(rhs._height),
|
||||
_varieties(rhs._varieties), _width(rhs._width), _height(rhs._height),
|
||||
_effect(rhs._effect)
|
||||
{}
|
||||
|
||||
@@ -255,7 +278,7 @@ struct AddTreesLeafObject
|
||||
void operator() (LOD* lod, const TreeBin::Tree& tree) const
|
||||
{
|
||||
Geode* geode = static_cast<Geode*>(lod->getChild(int(tree.position.x() * 10.0f) % lod->getNumChildren()));
|
||||
addTreeToLeafGeode(geode, tree.position);
|
||||
addTreeToLeafGeode(geode, tree.position, tree.tnormal);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -277,7 +300,8 @@ struct TreeTransformer
|
||||
TreeBin::Tree operator()(const TreeBin::Tree& tree) const
|
||||
{
|
||||
Vec3 pos = toOsg(tree.position);
|
||||
return TreeBin::Tree(toSG(pos * mat));
|
||||
Vec3 norm = toOsg(tree.tnormal);
|
||||
return TreeBin::Tree(toSG(pos * mat),toSG(norm * mat));
|
||||
}
|
||||
Matrix mat;
|
||||
};
|
||||
@@ -332,6 +356,20 @@ osg::Group* createForest(SGTreeBinList& forestList, const osg::Matrix& transform
|
||||
MatrixTransform* mt = new MatrixTransform(transform);
|
||||
|
||||
SGTreeBinList::iterator i;
|
||||
|
||||
use_tree_shadows = false;
|
||||
use_tree_normals = false;
|
||||
if (options) {
|
||||
SGPropertyNode* propertyNode = options->getPropertyNode().get();
|
||||
if (propertyNode) {
|
||||
use_tree_shadows
|
||||
= propertyNode->getBoolValue("/sim/rendering/random-vegetation-shadows",
|
||||
use_tree_shadows);
|
||||
use_tree_normals
|
||||
= propertyNode->getBoolValue("/sim/rendering/random-vegetation-normals",
|
||||
use_tree_normals);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = forestList.begin(); i != forestList.end(); ++i) {
|
||||
TreeBin* forest = *i;
|
||||
@@ -343,7 +381,7 @@ osg::Group* createForest(SGTreeBinList& forestList, const osg::Matrix& transform
|
||||
(!iter->second.lock(effect)))
|
||||
{
|
||||
SGPropertyNode_ptr effectProp = new SGPropertyNode;
|
||||
makeChild(effectProp, "inherits-from")->setStringValue("Effects/tree");
|
||||
makeChild(effectProp, "inherits-from")->setStringValue(forest->teffect);
|
||||
SGPropertyNode* params = makeChild(effectProp, "parameters");
|
||||
// emphasize n = 0
|
||||
params->getChild("texture", 0, true)->getChild("image", 0, true)
|
||||
|
||||
@@ -36,10 +36,10 @@ namespace simgear
|
||||
class TreeBin {
|
||||
public:
|
||||
struct Tree {
|
||||
Tree(const SGVec3f& p) :
|
||||
position(p)
|
||||
{ }
|
||||
SGVec3f position;
|
||||
SGVec3f tnormal;
|
||||
Tree(const SGVec3f& p, const SGVec3f& t) : position(p),tnormal(t)
|
||||
{ }
|
||||
};
|
||||
|
||||
typedef std::vector<Tree> TreeList;
|
||||
@@ -49,11 +49,13 @@ public:
|
||||
float height;
|
||||
float width;
|
||||
std::string texture;
|
||||
std::string teffect;
|
||||
|
||||
void insert(const Tree& t)
|
||||
{ _trees.push_back(t); }
|
||||
void insert(const SGVec3f& p, int t, float s)
|
||||
{ insert(Tree(p)); }
|
||||
|
||||
void insert(const SGVec3f& p, const SGVec3f& tnorm)
|
||||
{insert(Tree(p,tnorm));}
|
||||
|
||||
unsigned getNumTrees() const
|
||||
{ return _trees.size(); }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -70,7 +70,7 @@ static const bool svn_built_in_available = true;
|
||||
using namespace simgear;
|
||||
using namespace std;
|
||||
|
||||
const char* rsync_cmd =
|
||||
const char* rsync_cmd =
|
||||
"rsync --verbose --archive --delete --perms --owner --group";
|
||||
|
||||
const char* svn_options =
|
||||
@@ -121,30 +121,30 @@ public:
|
||||
SharedModels,
|
||||
AIData
|
||||
};
|
||||
|
||||
|
||||
enum Status
|
||||
{
|
||||
Invalid = 0,
|
||||
Waiting,
|
||||
Cached, ///< using already cached result
|
||||
Updated,
|
||||
NotFound,
|
||||
NotFound,
|
||||
Failed
|
||||
};
|
||||
|
||||
|
||||
SyncItem() :
|
||||
_dir(),
|
||||
_type(Stop),
|
||||
_status(Invalid)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SyncItem(string dir, Type ty) :
|
||||
_dir(dir),
|
||||
_type(ty),
|
||||
_status(Waiting)
|
||||
{}
|
||||
|
||||
|
||||
string _dir;
|
||||
Type _type;
|
||||
Status _status;
|
||||
@@ -164,14 +164,14 @@ public:
|
||||
isNewDirectory(false),
|
||||
busy(false)
|
||||
{}
|
||||
|
||||
|
||||
SyncItem currentItem;
|
||||
bool isNewDirectory;
|
||||
std::queue<SyncItem> queue;
|
||||
std::auto_ptr<SVNRepository> repository;
|
||||
SGTimeStamp stamp;
|
||||
bool busy; ///< is the slot working or idle
|
||||
|
||||
|
||||
unsigned int nextWarnTimeout;
|
||||
};
|
||||
|
||||
@@ -193,12 +193,49 @@ static unsigned int syncSlotForType(SyncItem::Type ty)
|
||||
return SYNC_SLOT_SHARED_DATA;
|
||||
case SyncItem::AIData:
|
||||
return SYNC_SLOT_AI_DATA;
|
||||
|
||||
|
||||
default:
|
||||
return SYNC_SLOT_SHARED_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Base server query
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class ServerSelectQuery : public HTTP::Request
|
||||
{
|
||||
public:
|
||||
ServerSelectQuery() :
|
||||
HTTP::Request("http://scenery.flightgear.org/svn-server", "GET")
|
||||
{
|
||||
}
|
||||
|
||||
std::string svnUrl() const
|
||||
{
|
||||
std::string s = simgear::strutils::strip(m_url);
|
||||
if (s.at(s.length() - 1) == '/') {
|
||||
s = s.substr(0, s.length() - 1);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
protected:
|
||||
virtual void gotBodyData(const char* s, int n)
|
||||
{
|
||||
m_url.append(std::string(s, n));
|
||||
}
|
||||
|
||||
virtual void onFail()
|
||||
{
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Failed to query TerraSync SVN server");
|
||||
HTTP::Request::onFail();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_url;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SGTerraSync::SvnThread /////////////////////////////////////////////////////
|
||||
@@ -220,7 +257,7 @@ public:
|
||||
|
||||
void setSvnServer(string server) { _svn_server = stripPath(server);}
|
||||
void setSvnDataServer(string server) { _svn_data_server = stripPath(server);}
|
||||
|
||||
|
||||
void setExtSvnUtility(string svn_util) { _svn_command = simgear::strutils::strip(svn_util);}
|
||||
void setRsyncServer(string server) { _rsync_server = simgear::strutils::strip(server);}
|
||||
void setLocalDir(string dir) { _local_dir = stripPath(dir);}
|
||||
@@ -245,10 +282,10 @@ public:
|
||||
volatile int _transfer_rate;
|
||||
// kbytes, not bytes, because bytes might overflow 2^31
|
||||
volatile int _total_kb_downloaded;
|
||||
|
||||
|
||||
private:
|
||||
virtual void run();
|
||||
|
||||
|
||||
// external model run and helpers
|
||||
void runExternal();
|
||||
void syncPathExternal(const SyncItem& next);
|
||||
@@ -259,14 +296,14 @@ private:
|
||||
void updateSyncSlot(SyncSlot& slot);
|
||||
|
||||
// commond helpers between both internal and external models
|
||||
|
||||
|
||||
SyncItem::Status isPathCached(const SyncItem& next) const;
|
||||
void initCompletedTilesPersistentCache();
|
||||
void writeCompletedTilesPersistentCache() const;
|
||||
void updated(SyncItem item, bool isNewDirectory);
|
||||
void fail(SyncItem failedItem);
|
||||
void notFound(SyncItem notFoundItem);
|
||||
|
||||
|
||||
bool _use_built_in;
|
||||
HTTP::Client _http;
|
||||
SyncSlot _syncSlots[NUM_SYNC_SLOTS];
|
||||
@@ -274,10 +311,10 @@ private:
|
||||
volatile bool _is_dirty;
|
||||
volatile bool _stop;
|
||||
SGBlockingDeque <SyncItem> waitingTiles;
|
||||
|
||||
|
||||
TileAgeCache _completedTiles;
|
||||
TileAgeCache _notFoundItems;
|
||||
|
||||
|
||||
SGBlockingDeque <SyncItem> _freshTiles;
|
||||
bool _use_svn;
|
||||
string _svn_server;
|
||||
@@ -363,14 +400,7 @@ bool SGTerraSync::SvnThread::start()
|
||||
|
||||
_use_svn |= _use_built_in;
|
||||
|
||||
if ((_use_svn)&&(_svn_server==""))
|
||||
{
|
||||
SG_LOG(SG_TERRAIN,SG_ALERT,
|
||||
"Cannot start scenery download. Subversion scenery server is undefined.");
|
||||
_fail_count++;
|
||||
_stalled = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((!_use_svn)&&(_rsync_server==""))
|
||||
{
|
||||
SG_LOG(SG_TERRAIN,SG_ALERT,
|
||||
@@ -437,7 +467,7 @@ bool SGTerraSync::SvnThread::runExternalSyncCommand(const char* dir)
|
||||
// windows command line parsing is just lovely...
|
||||
// to allow white spaces, the system call needs this:
|
||||
// ""C:\Program Files\something.exe" somearg "some other arg""
|
||||
// Note: whitespace strings quoted by a pair of "" _and_ the
|
||||
// Note: whitespace strings quoted by a pair of "" _and_ the
|
||||
// entire string needs to be wrapped by "" too.
|
||||
// The svn url needs forward slashes (/) as a path separator while
|
||||
// the local path needs windows-native backslash as a path separator.
|
||||
@@ -472,13 +502,39 @@ void SGTerraSync::SvnThread::run()
|
||||
{
|
||||
_active = true;
|
||||
initCompletedTilesPersistentCache();
|
||||
|
||||
|
||||
{
|
||||
if (_svn_server.empty()) {
|
||||
SG_LOG(SG_TERRAIN,SG_INFO, "Querying closest TerraSync server");
|
||||
ServerSelectQuery* ssq = new ServerSelectQuery;
|
||||
HTTP::Request_ptr req = ssq;
|
||||
_http.makeRequest(req);
|
||||
while (!req->isComplete()) {
|
||||
_http.update(20);
|
||||
}
|
||||
|
||||
if (req->readyState() == HTTP::Request::DONE) {
|
||||
_svn_server = ssq->svnUrl();
|
||||
SG_LOG(SG_TERRAIN,SG_INFO, "Closest TerraSync server:" << _svn_server);
|
||||
} else {
|
||||
SG_LOG(SG_TERRAIN,SG_WARN, "Failed to query closest TerraSync server");
|
||||
}
|
||||
} else {
|
||||
SG_LOG(SG_TERRAIN,SG_INFO, "Explicit: TerraSync server:" << _svn_server);
|
||||
}
|
||||
|
||||
if (_svn_server.empty()) {
|
||||
// default value
|
||||
_svn_server = "http://foxtrot.mgras.net:8080/terrascenery/trunk/data/Scenery";
|
||||
}
|
||||
}
|
||||
|
||||
if (_use_built_in) {
|
||||
runInternal();
|
||||
} else {
|
||||
runExternal();
|
||||
}
|
||||
|
||||
|
||||
_active = false;
|
||||
_running = false;
|
||||
_is_dirty = true;
|
||||
@@ -502,7 +558,7 @@ void SGTerraSync::SvnThread::runExternal()
|
||||
_is_dirty = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
syncPathExternal(next);
|
||||
|
||||
if ((_allowed_errors >= 0)&&
|
||||
@@ -520,7 +576,7 @@ void SGTerraSync::SvnThread::syncPathExternal(const SyncItem& next)
|
||||
SGPath path( _local_dir );
|
||||
path.append( next._dir );
|
||||
bool isNewDirectory = !path.exists();
|
||||
|
||||
|
||||
try {
|
||||
if (isNewDirectory) {
|
||||
int rc = path.create_dir( 0755 );
|
||||
@@ -530,7 +586,7 @@ void SGTerraSync::SvnThread::syncPathExternal(const SyncItem& next)
|
||||
throw sg_exception("Cannot create directory for terrasync", path.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!runExternalSyncCommand(next._dir.c_str())) {
|
||||
throw sg_exception("Running external sync command failed");
|
||||
}
|
||||
@@ -539,7 +595,7 @@ void SGTerraSync::SvnThread::syncPathExternal(const SyncItem& next)
|
||||
_busy = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
updated(next, isNewDirectory);
|
||||
_busy = false;
|
||||
}
|
||||
@@ -548,7 +604,7 @@ void SGTerraSync::SvnThread::updateSyncSlot(SyncSlot &slot)
|
||||
{
|
||||
if (slot.repository.get()) {
|
||||
if (slot.repository->isDoingSync()) {
|
||||
#if 0
|
||||
#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());
|
||||
@@ -557,7 +613,7 @@ void SGTerraSync::SvnThread::updateSyncSlot(SyncSlot &slot)
|
||||
#endif
|
||||
return; // easy, still working
|
||||
}
|
||||
|
||||
|
||||
// check result
|
||||
SVNRepository::ResultCode res = slot.repository->failure();
|
||||
if (res == SVNRepository::SVN_ERROR_NOT_FOUND) {
|
||||
@@ -574,12 +630,12 @@ void SGTerraSync::SvnThread::updateSyncSlot(SyncSlot &slot)
|
||||
slot.busy = false;
|
||||
slot.repository.reset();
|
||||
}
|
||||
|
||||
|
||||
// init and start sync of the next repository
|
||||
if (!slot.queue.empty()) {
|
||||
slot.currentItem = slot.queue.front();
|
||||
slot.queue.pop();
|
||||
|
||||
|
||||
SGPath path(_local_dir);
|
||||
path.append(slot.currentItem._dir);
|
||||
slot.isNewDirectory = !path.exists();
|
||||
@@ -592,20 +648,20 @@ void SGTerraSync::SvnThread::updateSyncSlot(SyncSlot &slot)
|
||||
return;
|
||||
}
|
||||
} // of creating directory step
|
||||
|
||||
|
||||
string serverUrl(_svn_server);
|
||||
if (slot.currentItem._type == SyncItem::AIData) {
|
||||
serverUrl = _svn_data_server;
|
||||
}
|
||||
|
||||
|
||||
slot.repository.reset(new SVNRepository(path, &_http));
|
||||
slot.repository->setBaseUrl(serverUrl + "/" + slot.currentItem._dir);
|
||||
slot.repository->update();
|
||||
|
||||
|
||||
slot.nextWarnTimeout = 20000;
|
||||
slot.stamp.stamp();
|
||||
slot.busy = true;
|
||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "sync of " << slot.repository->baseUrl() << " started, queue size is " << slot.queue.size());
|
||||
SG_LOG(SG_TERRAIN, SG_INFO, "sync of " << slot.repository->baseUrl() << " started, queue size is " << slot.queue.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,10 +672,10 @@ void SGTerraSync::SvnThread::runInternal()
|
||||
_transfer_rate = _http.transferRateBytesPerSec();
|
||||
// convert from bytes to kbytes
|
||||
_total_kb_downloaded = static_cast<int>(_http.totalBytesDownloaded() / 1024);
|
||||
|
||||
|
||||
if (_stop)
|
||||
break;
|
||||
|
||||
|
||||
// drain the waiting tiles queue into the sync slot queues.
|
||||
while (!waitingTiles.empty()) {
|
||||
SyncItem next = waitingTiles.pop_front();
|
||||
@@ -636,7 +692,7 @@ void SGTerraSync::SvnThread::runInternal()
|
||||
unsigned int slot = syncSlotForType(next._type);
|
||||
_syncSlots[slot].queue.push(next);
|
||||
}
|
||||
|
||||
|
||||
bool anySlotBusy = false;
|
||||
// update each sync slot in turn
|
||||
for (unsigned int slot=0; slot < NUM_SYNC_SLOTS; ++slot) {
|
||||
@@ -663,7 +719,7 @@ SyncItem::Status SGTerraSync::SvnThread::isPathCached(const SyncItem& next) cons
|
||||
// higher levels the cache status
|
||||
return (ii == _notFoundItems.end()) ? SyncItem::Invalid : SyncItem::NotFound;
|
||||
}
|
||||
|
||||
|
||||
// check if the path still physically exists. This is needed to
|
||||
// cope with the user manipulating our cache dir
|
||||
SGPath p(_local_dir);
|
||||
@@ -671,7 +727,7 @@ SyncItem::Status SGTerraSync::SvnThread::isPathCached(const SyncItem& next) cons
|
||||
if (!p.exists()) {
|
||||
return SyncItem::Invalid;
|
||||
}
|
||||
|
||||
|
||||
time_t now = time(0);
|
||||
return (ii->second > now) ? SyncItem::Cached : SyncItem::Invalid;
|
||||
}
|
||||
@@ -683,6 +739,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 << "'");
|
||||
_completedTiles[ failedItem._dir ] = now + UpdateInterval::FailedAttempt;
|
||||
_is_dirty = true;
|
||||
}
|
||||
@@ -693,7 +751,7 @@ void SGTerraSync::SvnThread::notFound(SyncItem item)
|
||||
// as succesful download. Important for MP models and similar so
|
||||
// we don't spam the server with lookups for models that don't
|
||||
// exist
|
||||
|
||||
|
||||
time_t now = time(0);
|
||||
item._status = SyncItem::NotFound;
|
||||
_freshTiles.push_back(item);
|
||||
@@ -709,7 +767,7 @@ void SGTerraSync::SvnThread::updated(SyncItem item, bool isNewDirectory)
|
||||
_success_count++;
|
||||
SG_LOG(SG_TERRAIN,SG_INFO,
|
||||
"Successfully synchronized directory '" << item._dir << "'");
|
||||
|
||||
|
||||
item._status = SyncItem::Updated;
|
||||
if (item._type == SyncItem::Tile) {
|
||||
_updated_tile_count++;
|
||||
@@ -726,17 +784,17 @@ void SGTerraSync::SvnThread::initCompletedTilesPersistentCache()
|
||||
if (!_persistentCachePath.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SGPropertyNode_ptr cacheRoot(new SGPropertyNode);
|
||||
time_t now = time(0);
|
||||
|
||||
|
||||
try {
|
||||
readProperties(_persistentCachePath.str(), cacheRoot);
|
||||
} catch (sg_exception& e) {
|
||||
SG_LOG(SG_TERRAIN, SG_INFO, "corrupted persistent cache, discarding");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (int i=0; i<cacheRoot->nChildren(); ++i) {
|
||||
SGPropertyNode* entry = cacheRoot->getChild(i);
|
||||
bool isNotFound = (strcmp(entry->getName(), "not-found") == 0);
|
||||
@@ -745,7 +803,7 @@ void SGTerraSync::SvnThread::initCompletedTilesPersistentCache()
|
||||
if (stamp < now) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (isNotFound) {
|
||||
_completedTiles[tileName] = stamp;
|
||||
} else {
|
||||
@@ -760,12 +818,12 @@ void SGTerraSync::SvnThread::writeCompletedTilesPersistentCache() const
|
||||
if (_persistentCachePath.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
std::ofstream f(_persistentCachePath.c_str(), std::ios::trunc);
|
||||
if (!f.is_open()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SGPropertyNode_ptr cacheRoot(new SGPropertyNode);
|
||||
TileAgeCache::const_iterator it = _completedTiles.begin();
|
||||
for (; it != _completedTiles.end(); ++it) {
|
||||
@@ -773,14 +831,14 @@ void SGTerraSync::SvnThread::writeCompletedTilesPersistentCache() const
|
||||
entry->setStringValue("path", it->first);
|
||||
entry->setIntValue("stamp", it->second);
|
||||
}
|
||||
|
||||
|
||||
it = _notFoundItems.begin();
|
||||
for (; it != _notFoundItems.end(); ++it) {
|
||||
SGPropertyNode* entry = cacheRoot->addChild("not-found");
|
||||
entry->setStringValue("path", it->first);
|
||||
entry->setIntValue("stamp", it->second);
|
||||
}
|
||||
|
||||
|
||||
writeProperties(f, cacheRoot, true /* write_all */);
|
||||
f.close();
|
||||
}
|
||||
@@ -796,7 +854,7 @@ SGTerraSync::SGTerraSync() :
|
||||
_svnThread = new SvnThread();
|
||||
_log = new BufferedLogCallback(SG_TERRAIN, SG_INFO);
|
||||
_log->truncateAt(255);
|
||||
|
||||
|
||||
sglog().addCallback(_log);
|
||||
}
|
||||
|
||||
@@ -819,12 +877,12 @@ void SGTerraSync::init()
|
||||
if (_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_inited = true;
|
||||
|
||||
|
||||
assert(_terraRoot);
|
||||
_terraRoot->setBoolValue("built-in-svn-available",svn_built_in_available);
|
||||
|
||||
|
||||
reinit();
|
||||
}
|
||||
|
||||
@@ -841,7 +899,7 @@ void SGTerraSync::reinit()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_svnThread->stop();
|
||||
|
||||
if (_terraRoot->getBoolValue("enabled",false))
|
||||
@@ -871,7 +929,7 @@ void SGTerraSync::bind()
|
||||
if (_bound) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_bound = true;
|
||||
_tiedProperties.Tie( _terraRoot->getNode("busy", true), (bool*) &_svnThread->_busy );
|
||||
_tiedProperties.Tie( _terraRoot->getNode("active", true), (bool*) &_svnThread->_active );
|
||||
@@ -880,11 +938,11 @@ void SGTerraSync::bind()
|
||||
_tiedProperties.Tie( _terraRoot->getNode("tile-count", true), (int*) &_svnThread->_updated_tile_count );
|
||||
_tiedProperties.Tie( _terraRoot->getNode("cache-hits", true), (int*) &_svnThread->_cache_hits );
|
||||
_tiedProperties.Tie( _terraRoot->getNode("transfer-rate-bytes-sec", true), (int*) &_svnThread->_transfer_rate );
|
||||
|
||||
|
||||
// use kbytes here because propety doesn't support 64-bit and we might conceivably
|
||||
// download more than 2G in a single session
|
||||
_tiedProperties.Tie( _terraRoot->getNode("downloaded-kbytes", true), (int*) &_svnThread->_total_kb_downloaded );
|
||||
|
||||
|
||||
_terraRoot->getNode("busy", true)->setAttribute(SGPropertyNode::WRITE,false);
|
||||
_terraRoot->getNode("active", true)->setAttribute(SGPropertyNode::WRITE,false);
|
||||
_terraRoot->getNode("update-count", true)->setAttribute(SGPropertyNode::WRITE,false);
|
||||
@@ -904,7 +962,7 @@ void SGTerraSync::unbind()
|
||||
_tiedProperties.Untie();
|
||||
_bound = false;
|
||||
_inited = false;
|
||||
|
||||
|
||||
_terraRoot.clear();
|
||||
_stalledNode.clear();
|
||||
_cacheHits.clear();
|
||||
@@ -934,7 +992,7 @@ void SGTerraSync::update(double)
|
||||
while (_svnThread->hasNewTiles())
|
||||
{
|
||||
SyncItem next = _svnThread->getNewTile();
|
||||
|
||||
|
||||
if ((next._type == SyncItem::Tile) || (next._type == SyncItem::AIData)) {
|
||||
_activeTileDirs.erase(next._dir);
|
||||
}
|
||||
@@ -958,7 +1016,7 @@ void SGTerraSync::syncAirportsModels()
|
||||
_svnThread->request( w );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SyncItem w("Models", SyncItem::SharedModels);
|
||||
_svnThread->request( w );
|
||||
}
|
||||
@@ -972,7 +1030,7 @@ void SGTerraSync::syncAreaByPath(const std::string& aPath)
|
||||
if (_activeTileDirs.find(dir) != _activeTileDirs.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
_activeTileDirs.insert(dir);
|
||||
SyncItem w(dir, SyncItem::Tile);
|
||||
_svnThread->request( w );
|
||||
@@ -991,7 +1049,7 @@ bool SGTerraSync::isTileDirPending(const std::string& sceneryDir) const
|
||||
if (!_svnThread->_running) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const char* terrainobjects[3] = { "Terrain/", "Objects/", 0 };
|
||||
for (const char** tree = &terrainobjects[0]; *tree; tree++) {
|
||||
string s = *tree + sceneryDir;
|
||||
@@ -1008,7 +1066,7 @@ void SGTerraSync::scheduleDataDir(const std::string& dataDir)
|
||||
if (_activeTileDirs.find(dataDir) != _activeTileDirs.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_activeTileDirs.insert(dataDir);
|
||||
SyncItem w(dataDir, SyncItem::AIData);
|
||||
_svnThread->request( w );
|
||||
@@ -1020,7 +1078,7 @@ bool SGTerraSync::isDataDirPending(const std::string& dataDir) const
|
||||
if (!_svnThread->_running) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return (_activeTileDirs.find(dataDir) != _activeTileDirs.end());
|
||||
}
|
||||
|
||||
|
||||
@@ -25,11 +25,13 @@
|
||||
|
||||
#include "SGSceneFeatures.hxx"
|
||||
|
||||
#include <osg/Version>
|
||||
#include <osg/FragmentProgram>
|
||||
#include <osg/VertexProgram>
|
||||
#include <osg/Point>
|
||||
#include <osg/PointSprite>
|
||||
#include <osg/Texture>
|
||||
#include <osg/GLExtensions>
|
||||
|
||||
#include <OpenThreads/Mutex>
|
||||
#include <OpenThreads/ScopedLock>
|
||||
@@ -84,12 +86,18 @@ SGSceneFeatures::setTextureCompression(osg::Texture* texture) const
|
||||
bool
|
||||
SGSceneFeatures::getHavePointSprites(unsigned contextId) const
|
||||
{
|
||||
#if OSG_VERSION_LESS_THAN(3,3,4)
|
||||
return osg::PointSprite::isPointSpriteSupported(contextId);
|
||||
#else
|
||||
const osg::GLExtensions* ex = osg::GLExtensions::Get(contextId, true);
|
||||
return ex && ex->isPointSpriteSupported;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
SGSceneFeatures::getHaveFragmentPrograms(unsigned contextId) const
|
||||
{
|
||||
#if OSG_VERSION_LESS_THAN(3,3,4)
|
||||
const osg::FragmentProgram::Extensions* fpe;
|
||||
fpe = osg::FragmentProgram::getExtensions(contextId, true);
|
||||
if (!fpe)
|
||||
@@ -98,11 +106,16 @@ SGSceneFeatures::getHaveFragmentPrograms(unsigned contextId) const
|
||||
return false;
|
||||
|
||||
return true;
|
||||
#else
|
||||
const osg::GLExtensions* ex = osg::GLExtensions::Get(contextId, true);
|
||||
return ex && ex->isFragmentProgramSupported;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
SGSceneFeatures::getHaveVertexPrograms(unsigned contextId) const
|
||||
{
|
||||
#if OSG_VERSION_LESS_THAN(3,3,4)
|
||||
const osg::VertexProgram::Extensions* vpe;
|
||||
vpe = osg::VertexProgram::getExtensions(contextId, true);
|
||||
if (!vpe)
|
||||
@@ -111,6 +124,10 @@ SGSceneFeatures::getHaveVertexPrograms(unsigned contextId) const
|
||||
return false;
|
||||
|
||||
return true;
|
||||
#else
|
||||
const osg::GLExtensions* ex = osg::GLExtensions::Get(contextId, true);
|
||||
return ex && ex->isVertexProgramSupported;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -124,6 +141,7 @@ SGSceneFeatures::getHaveShaderPrograms(unsigned contextId) const
|
||||
bool
|
||||
SGSceneFeatures::getHavePointParameters(unsigned contextId) const
|
||||
{
|
||||
#if OSG_VERSION_LESS_THAN(3,3,4)
|
||||
const osg::Point::Extensions* pe;
|
||||
pe = osg::Point::getExtensions(contextId, true);
|
||||
if (!pe)
|
||||
@@ -131,5 +149,9 @@ SGSceneFeatures::getHavePointParameters(unsigned contextId) const
|
||||
if (!pe->isPointParametersSupported())
|
||||
return false;
|
||||
return true;
|
||||
#else
|
||||
const osg::GLExtensions* ex = osg::GLExtensions::Get(contextId, true);
|
||||
return ex && ex->isPointParametersSupported;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ using namespace osg;
|
||||
|
||||
void UpdateOnceCallback::operator()(Node* node, NodeVisitor* nv)
|
||||
{
|
||||
ref_ptr<UpdateOnceCallback> prevent_premature_deletion=this;
|
||||
// workaround for crash bug in OSG 3.2.1
|
||||
// https://bugs.debian.org/765855
|
||||
doUpdate(node, nv);
|
||||
node->removeUpdateCallback(this);
|
||||
// The callback could be deleted now.
|
||||
|
||||
@@ -401,8 +401,9 @@ void SGSampleGroup::set_volume( float vol )
|
||||
|
||||
// set the source position and orientation of all managed sounds
|
||||
void SGSampleGroup::update_pos_and_orientation() {
|
||||
|
||||
SGVec3d position = SGVec3d::fromGeod(_base_pos) - _smgr->get_position();
|
||||
|
||||
SGVec3d base_position = SGVec3d::fromGeod(_base_pos);
|
||||
SGVec3d smgr_position = _smgr->get_position();
|
||||
SGQuatd hlOr = SGQuatd::fromLonLat(_base_pos);
|
||||
SGQuatd ec2body = hlOr*_orientation;
|
||||
|
||||
@@ -418,12 +419,14 @@ void SGSampleGroup::update_pos_and_orientation() {
|
||||
sample->set_master_volume( _volume );
|
||||
sample->set_orientation( _orientation );
|
||||
sample->set_rotation( ec2body );
|
||||
sample->set_position( position );
|
||||
sample->set_position(base_position);
|
||||
sample->set_velocity( velocity );
|
||||
|
||||
// Test if a sample is farther away than max distance, if so
|
||||
// stop the sound playback and free it's source.
|
||||
if (!_tied_to_listener) {
|
||||
sample->update_pos_and_orientation();
|
||||
SGVec3d position = sample->get_position() - smgr_position;
|
||||
float max2 = sample->get_max_dist() * sample->get_max_dist();
|
||||
float dist2 = position[0]*position[0]
|
||||
+ position[1]*position[1] + position[2]*position[2];
|
||||
@@ -449,7 +452,7 @@ void SGSampleGroup::update_sample_config( SGSoundSample *sample )
|
||||
} else {
|
||||
sample->update_pos_and_orientation();
|
||||
orientation = sample->get_orientation();
|
||||
position = sample->get_position();
|
||||
position = sample->get_position() - _smgr->get_position();
|
||||
velocity = sample->get_velocity();
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ void SampleHistogram::reset ()
|
||||
this->SampleStatistic::reset ();
|
||||
if (howManyBuckets > 0)
|
||||
{
|
||||
for (register int i = 0; i < howManyBuckets; i++)
|
||||
for (int i = 0; i < howManyBuckets; i++)
|
||||
{
|
||||
bucketCount[i] = 0;
|
||||
}
|
||||
|
||||
@@ -439,9 +439,9 @@ void StateMachine::initFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
|
||||
std::string nm = stateDesc->getStringValue("name");
|
||||
State_ptr st(new State(nm));
|
||||
|
||||
readBindingList(stateDesc, "enter", root, st->d->_updateBindings);
|
||||
readBindingList(stateDesc, "exit", root, st->d->_entryBindings);
|
||||
readBindingList(stateDesc, "update", root, st->d->_exitBindings);
|
||||
readBindingList(stateDesc, "enter", root, st->d->_entryBindings);
|
||||
readBindingList(stateDesc, "update", root, st->d->_updateBindings);
|
||||
readBindingList(stateDesc, "exit", root, st->d->_exitBindings);
|
||||
|
||||
addState(st);
|
||||
} // of states iteration
|
||||
@@ -456,7 +456,7 @@ void StateMachine::initFromPlist(SGPropertyNode* desc, SGPropertyNode* root)
|
||||
t->setTriggerCondition(cond);
|
||||
|
||||
t->setExcludeTarget(tDesc->getBoolValue("exclude-target", true));
|
||||
BOOST_FOREACH(SGPropertyNode* src, desc->getChildren("source")) {
|
||||
BOOST_FOREACH(SGPropertyNode* src, tDesc->getChildren("source")) {
|
||||
State_ptr srcState = findStateByName(src->getStringValue());
|
||||
t->addSourceState(srcState);
|
||||
}
|
||||
|
||||
@@ -58,8 +58,11 @@ void SGEventMgr::unbind()
|
||||
void SGEventMgr::init()
|
||||
{
|
||||
if (_inited) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "duplicate init of SGEventMgr");
|
||||
// protected against duplicate calls here, in case
|
||||
// init ever does something more complex in the future.
|
||||
return;
|
||||
}
|
||||
|
||||
_inited = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
|
||||
/* BIG FAT WARNING: NOTICE THAT I HARDCODED ENDIANNES. PLEASE CHANGE THIS */
|
||||
#ifndef BIG_ENDIAN
|
||||
#ifndef BIG_ENDIAN
|
||||
#define BIG_ENDIAN 4321
|
||||
#endif
|
||||
|
||||
@@ -55,13 +55,13 @@
|
||||
#define LITTLE_ENDIAN 1234
|
||||
#endif
|
||||
|
||||
#ifndef BYTE_ORDER
|
||||
#ifndef BYTE_ORDER
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BYTE_ORDER
|
||||
#define BYTE_ORDER
|
||||
#define BYTE_ORDER
|
||||
#endif
|
||||
|
||||
/* END OF BIG FAT WARNING */
|
||||
@@ -267,7 +267,7 @@ void show(const char *zone, time_t t, int v)
|
||||
|
||||
static char *abbr(struct tm *tmp)
|
||||
{
|
||||
register char * result;
|
||||
char * result;
|
||||
static char nada;
|
||||
|
||||
if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
|
||||
@@ -329,21 +329,21 @@ static void fgtzset_internal (int always, const char *tz)
|
||||
fgtzfile_read (tz);
|
||||
if (use_fgtzfile)
|
||||
return;
|
||||
// The default behaviour of the original tzset_internal (int always, char* tz)
|
||||
// The default behaviour of the original tzset_internal (int always, char* tz)
|
||||
// function is to set up a default timezone, in any case file_read() fails
|
||||
// Currently this leads to problems, because it modifies the system timezone
|
||||
// and not the local aircraft timezone, contained in FlightGear. I could adapt
|
||||
// and not the local aircraft timezone, contained in FlightGear. I could adapt
|
||||
// this in future versions of this code, but doubt whether this is what we really
|
||||
// want. So right now, throw an exception when timezone information reading failed.
|
||||
// want. So right now, throw an exception when timezone information reading failed.
|
||||
// Guess I'll change that to something like 12 * (FG_LON / 180.0)
|
||||
//
|
||||
//
|
||||
// For now, I'll leave it like this.
|
||||
else
|
||||
{
|
||||
throw sg_exception("Timezone reading failed");
|
||||
}
|
||||
// this emacs "comment out" function is cool!
|
||||
|
||||
|
||||
// // /* No data file found. Default to UTC if nothing specified. */
|
||||
// // printf ("1. Current local time = %24s", asctime(localtime(&now)));
|
||||
// if (tz == NULL || *tz == '\0')
|
||||
@@ -580,7 +580,7 @@ static void fgtzset_internal (int always, const char *tz)
|
||||
// tzr->computed_for = -1;
|
||||
// }
|
||||
// // printf ("10. Current local time = %24s", asctime(localtime(&now)));
|
||||
//
|
||||
//
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
@@ -627,7 +627,7 @@ static int fgcompute_change (fgtz_rule *rule, int year)
|
||||
// tz_rule *rule;
|
||||
// int year;
|
||||
{
|
||||
register time_t t;
|
||||
time_t t;
|
||||
int y;
|
||||
|
||||
if (year != -1 && rule->computed_for == year)
|
||||
@@ -660,8 +660,8 @@ static int fgcompute_change (fgtz_rule *rule, int year)
|
||||
case fgtz_rule::M:
|
||||
/* Mm.n.d - Nth "Dth day" of month M. */
|
||||
{
|
||||
register int i, d, m1, yy0, yy1, yy2, dow;
|
||||
register const unsigned short int *myday =
|
||||
int i, d, m1, yy0, yy1, yy2, dow;
|
||||
const unsigned short int *myday =
|
||||
&mon_yday[isleap (year)][rule->m];
|
||||
|
||||
/* First add SECSPERDAY for each day in months before M. */
|
||||
@@ -707,7 +707,7 @@ static int fgcompute_change (fgtz_rule *rule, int year)
|
||||
int fgtzfile_compute (time_t timer, int use_localtime,
|
||||
long int *leap_correct, int *leap_hit)
|
||||
{
|
||||
register size_t i;
|
||||
size_t i;
|
||||
|
||||
if (use_localtime)
|
||||
{
|
||||
@@ -788,10 +788,10 @@ void fgtzfile_read (const char *file)
|
||||
{
|
||||
// static const char default_tzdir[] = TZDIR;
|
||||
size_t num_isstd, num_isgmt;
|
||||
register FILE *f;
|
||||
FILE *f;
|
||||
struct tzhead tzhead;
|
||||
size_t chars;
|
||||
register size_t i;
|
||||
size_t i;
|
||||
struct ttinfo *info;
|
||||
|
||||
use_fgtzfile = 0;
|
||||
@@ -1046,8 +1046,8 @@ void offtime (const time_t *t, long int offset, struct tm *tp)
|
||||
// long int offset;
|
||||
// struct tm *tp;
|
||||
{
|
||||
register long int days, rem, y;
|
||||
register const unsigned short int *ip;
|
||||
long int days, rem, y;
|
||||
const unsigned short int *ip;
|
||||
|
||||
days = *t / SECS_PER_DAY;
|
||||
rem = *t % SECS_PER_DAY;
|
||||
@@ -1145,7 +1145,7 @@ time_t sgGMTime()
|
||||
// http://linux.die.net/man/3/timegm
|
||||
// but for the moment we'll assume time(0) on Unix is UTC, and hence we
|
||||
// return it directly.
|
||||
|
||||
|
||||
time_t now_sec = time(0);
|
||||
#if defined(SG_WINDOWS)
|
||||
struct tm now;
|
||||
|
||||
Reference in New Issue
Block a user