Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package SimGear for openSUSE:Factory checked in at 2023-03-30 22:51:44
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/SimGear (Old)
and /work/SRC/openSUSE:Factory/.SimGear.new.31432 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "SimGear"
Thu Mar 30 22:51:44 2023 rev:29 rq:1075536 version:2020.3.18
Changes:
--------
--- /work/SRC/openSUSE:Factory/SimGear/SimGear.changes 2023-03-06 18:55:57.680790224 +0100
+++ /work/SRC/openSUSE:Factory/.SimGear.new.31432/SimGear.changes 2023-03-30 22:51:46.244736531 +0200
@@ -1,0 +2,6 @@
+Wed Mar 29 10:28:29 UTC 2023 - Stefan Br��ns
+
+- Update to 2020.3.18
+ * https://wiki.flightgear.org/Changelog_2020.3#2020.3.18
+
+-------------------------------------------------------------------
Old:
----
simgear-2020.3.17.tar.bz2
New:
----
simgear-2020.3.18.tar.bz2
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ SimGear.spec ++++++
--- /var/tmp/diff_new_pack.1RcbFW/_old 2023-03-30 22:51:46.800739506 +0200
+++ /var/tmp/diff_new_pack.1RcbFW/_new 2023-03-30 22:51:46.804739528 +0200
@@ -20,10 +20,10 @@
# in our requirements, i.e. the same version we have built against
%define openscenegraph_version %(rpm -qa --nosignature --nodigest libOpenSceneGraph\*-devel | sed 's/.*-devel-\\(.*\\)-.*/\\1/')
-%define libname libSimGearCore-2020_3_17
+%define libname libSimGearCore-2020_3_18
%define main_version 2020.3
Name: SimGear
-Version: %{main_version}.17
+Version: %{main_version}.18
Release: 0
Summary: Simulator Construction Gear
# https://sourceforge.net/p/flightgear/codetickets/1940/
++++++ simgear-2020.3.17.tar.bz2 -> simgear-2020.3.18.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/simgear-2020.3.17/simgear/environment/test_metar.cxx new/simgear-2020.3.18/simgear/environment/test_metar.cxx
--- old/simgear-2020.3.17/simgear/environment/test_metar.cxx 2022-11-20 19:01:30.000000000 +0100
+++ new/simgear-2020.3.18/simgear/environment/test_metar.cxx 2023-03-14 08:49:42.000000000 +0100
@@ -123,6 +123,14 @@
#endif
}
+void test_EDQM_failure()
+{
+ //
+
+ SGMetar m1("2022/12/11 19:50 EDQM 111950Z AUTO VRB03KT 2700 // ///026/// M06/M07 Q1006");
+
+}
+
int main(int argc, char* argv[])
{
try {
@@ -134,6 +142,7 @@
test_clouds_without_height();
test_GLRB_failure();
test_LOWK_failure();
+ test_EDQM_failure();
} catch (sg_exception& e) {
cerr << "got exception:" << e.getMessage() << endl;
return -1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/simgear-2020.3.17/simgear/io/sg_binobj.hxx new/simgear-2020.3.18/simgear/io/sg_binobj.hxx
--- old/simgear-2020.3.17/simgear/io/sg_binobj.hxx 2022-11-20 19:01:30.000000000 +0100
+++ new/simgear-2020.3.18/simgear/io/sg_binobj.hxx 2023-03-14 08:49:42.000000000 +0100
@@ -150,6 +150,7 @@
std::vector<SGVec4f> colors; // color list
std::vector<SGVec3f> normals; // normal list
std::vector<SGVec2f> texcoords; // texture coordinate list
+ std::vector<SGVec2f> overlaycoords; // overlay texture coordinate list
std::vector<float> va_flt; // vertex attribute list (floats)
std::vector<int> va_int; // vertex attribute list (ints)
@@ -226,6 +227,10 @@
inline const std::vector<SGVec2f>& get_texcoords() const { return texcoords; }
inline void set_texcoords( const std::vector<SGVec2f>& t ) { texcoords = t; }
+
+ inline const std::vector<SGVec2f>& get_overlaycoords() const { return overlaycoords; }
+ inline void set_overlaycoords( const std::vector<SGVec2f>& t ) { overlaycoords = t; }
+
// Points API
bool add_point( const SGBinObjectPoint& pt );
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/simgear-2020.3.17/simgear/misc/sg_path.cxx new/simgear-2020.3.18/simgear/misc/sg_path.cxx
--- old/simgear-2020.3.17/simgear/misc/sg_path.cxx 2022-11-20 19:01:30.000000000 +0100
+++ new/simgear-2020.3.18/simgear/misc/sg_path.cxx 2023-03-14 08:49:42.000000000 +0100
@@ -484,7 +484,7 @@
}
//------------------------------------------------------------------------------
-void SGPath::updateAttrsIfNull() const
+void SGPath::updateCachedAttributes() const
{
if (_cached && _cacheEnabled) {
return;
@@ -570,7 +570,7 @@
return;
}
- updateAttrsIfNull();
+ updateCachedAttributes();
_rwCached = true;
}
@@ -589,7 +589,7 @@
return _exists;
}
#endif
- updateAttrsIfNull();
+ updateCachedAttributes();
return _exists;
}
@@ -609,13 +609,13 @@
bool SGPath::isDir() const
{
- updateAttrsIfNull();
+ updateCachedAttributes();
return _exists && _isDir;
}
bool SGPath::isFile() const
{
- updateAttrsIfNull();
+ updateCachedAttributes();
return _exists && _isFile;
}
@@ -807,13 +807,13 @@
time_t SGPath::modTime() const
{
- updateAttrsIfNull();
+ updateCachedAttributes();
return _modTime;
}
size_t SGPath::sizeInBytes() const
{
- updateAttrsIfNull();
+ updateCachedAttributes();
return _size;
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/simgear-2020.3.17/simgear/misc/sg_path.hxx new/simgear-2020.3.18/simgear/misc/sg_path.hxx
--- old/simgear-2020.3.17/simgear/misc/sg_path.hxx 2022-11-20 19:01:30.000000000 +0100
+++ new/simgear-2020.3.18/simgear/misc/sg_path.hxx 2023-03-14 08:49:42.000000000 +0100
@@ -372,7 +372,7 @@
void fix();
- void updateAttrsIfNull() const;
+ void updateCachedAttributes() const;
void checkAccess() const;
bool permissionsAllowsWrite() const;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/simgear-2020.3.17/simgear/scene/model/SGText.cxx new/simgear-2020.3.18/simgear/scene/model/SGText.cxx
--- old/simgear-2020.3.17/simgear/scene/model/SGText.cxx 2022-11-20 19:01:30.000000000 +0100
+++ new/simgear-2020.3.18/simgear/scene/model/SGText.cxx 2023-03-14 08:49:42.000000000 +0100
@@ -23,6 +23,13 @@
#include "SGText.hxx"
+#include
+#include
+#include
+#include
+#include
+#include
+
#include
#include
#include
@@ -96,9 +103,16 @@
SGConstPropertyNode_ptr p;
osgText::Text * text = new osgText::Text();
- osg::Geode * g = new osg::Geode;
+ simgear::EffectGeode * g = new simgear::EffectGeode;
g->addDrawable( text );
+ SGPropertyNode_ptr effectProp = new SGPropertyNode;
+ makeChild(effectProp, "inherits-from")->setStringValue("Effects/text-default");
+ simgear::Effect* effect = simgear::makeEffect(
+ effectProp, true, dynamic_cast(options));
+ if (effect)
+ g->setEffect(effect);
+
const std::string requestedFont = configNode->getStringValue("font","Helvetica");
const SGPath fontPath = simgear::ResourceManager::instance()->findPath("Fonts/" + requestedFont);
if ( !fontPath.isNull() ) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/simgear-2020.3.17/simgear/scene/tgdb/SGTexturedTriangleBin.hxx new/simgear-2020.3.18/simgear/scene/tgdb/SGTexturedTriangleBin.hxx
--- old/simgear-2020.3.17/simgear/scene/tgdb/SGTexturedTriangleBin.hxx 2022-11-20 19:01:30.000000000 +0100
+++ new/simgear-2020.3.18/simgear/scene/tgdb/SGTexturedTriangleBin.hxx 2023-03-14 08:49:42.000000000 +0100
@@ -89,10 +89,15 @@
}
const SGVec2f& GetTexCoord( unsigned idx ) const { return texCoord[idx]; }
+ void SetOverlayCoord( const SGVec2f& ovc ) { overlayCoord = ovc; }
+ const SGVec2f& GetOverlayCoord() const { return overlayCoord; }
+
+
private:
SGVec3f vertex;
SGVec3f normal;
SGVec2f texCoord[4];
+ SGVec2f overlayCoord;
unsigned tc_mask;
};
@@ -432,6 +437,8 @@
osg::ref_ptrosg::Vec3Array normals = new osg::Vec3Array;
osg::ref_ptrosg::Vec2Array priTexCoords = new osg::Vec2Array;
osg::ref_ptrosg::Vec2Array secTexCoords = new osg::Vec2Array;
+ osg::ref_ptrosg::Vec2Array overlayCoords = new osg::Vec2Array;
+
osg::ref_ptrosg::Vec4Array colors = new osg::Vec4Array;
colors->push_back(osg::Vec4(1, 1, 1, 1));
@@ -453,7 +460,9 @@
geometry->setTexCoordArray(1, secTexCoords);
} else {
geometry->setTexCoordArray(0, priTexCoords);
- }
+ }
+ geometry->setVertexAttribArray(14, overlayCoords.get(), osg::Array::BIND_PER_VERTEX);
+
const unsigned invalid = ~unsigned(0);
std::vector<unsigned> indexMap(getNumVertices(), invalid);
@@ -469,6 +478,7 @@
if ( has_sec_tcs ) {
secTexCoords->push_back(toOsg(getVertex(triangle[0]).GetTexCoord(1)));
}
+ overlayCoords->push_back(toOsg(getVertex(triangle[0]).GetOverlayCoord()));
}
deFacade.push_back(indexMap[triangle[0]]);
@@ -480,6 +490,7 @@
if ( has_sec_tcs ) {
secTexCoords->push_back(toOsg(getVertex(triangle[1]).GetTexCoord(1)));
}
+ overlayCoords->push_back(toOsg(getVertex(triangle[1]).GetOverlayCoord()));
}
deFacade.push_back(indexMap[triangle[1]]);
@@ -491,6 +502,7 @@
if ( has_sec_tcs ) {
secTexCoords->push_back(toOsg(getVertex(triangle[2]).GetTexCoord(1)));
}
+ overlayCoords->push_back(toOsg(getVertex(triangle[2]).GetOverlayCoord()));
}
deFacade.push_back(indexMap[triangle[2]]);
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/simgear-2020.3.17/simgear/scene/tgdb/SGTileGeometryBin.hxx new/simgear-2020.3.18/simgear/scene/tgdb/SGTileGeometryBin.hxx
--- old/simgear-2020.3.17/simgear/scene/tgdb/SGTileGeometryBin.hxx 2022-11-20 19:01:30.000000000 +0100
+++ new/simgear-2020.3.18/simgear/scene/tgdb/SGTileGeometryBin.hxx 2023-03-14 08:49:42.000000000 +0100
@@ -58,6 +58,7 @@
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 std::vector<SGVec2f>& overlayCoords(obj.get_overlaycoords());
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]);
@@ -82,6 +83,8 @@
if (!tris_tc[1].empty()) {
v0.SetTexCoord( 1, getTexCoord(texCoords, tris_tc[1], tc1Scale, i-2) );
}
+ v0.SetOverlayCoord(overlayCoords[tris_v[i-2]]);
+
SGVertNormTex v1;
v1.SetVertex( toVec3f(vertices[tris_v[i-1]]) );
v1.SetNormal( num_norms_is_num_verts ? normals[tris_n[i-1]] :
@@ -90,6 +93,8 @@
if (!tris_tc[1].empty()) {
v1.SetTexCoord( 1, getTexCoord(texCoords, tris_tc[1], tc1Scale, i-1) );
}
+ v1.SetOverlayCoord(overlayCoords[tris_v[i-1]]);
+
SGVertNormTex v2;
v2.SetVertex( toVec3f(vertices[tris_v[i]]) );
v2.SetNormal( num_norms_is_num_verts ? normals[tris_n[i]] :
@@ -98,6 +103,8 @@
if (!tris_tc[1].empty()) {
v2.SetTexCoord( 1, getTexCoord(texCoords, tris_tc[1], tc1Scale, i) );
}
+ v2.SetOverlayCoord(overlayCoords[tris_v[i]]);
+
triangles.insert(v0, v1, v2);
}
@@ -168,6 +175,7 @@
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 std::vector<SGVec2f>& overlayCoords(obj.get_overlaycoords());
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]);
@@ -191,6 +199,8 @@
if (!fans_tc[1].empty()) {
v0.SetTexCoord( 1, getTexCoord(texCoords, fans_tc[1], tc1Scale, 0) );
}
+ v0.SetOverlayCoord(overlayCoords[fans_v[0]]);
+
SGVertNormTex v1;
v1.SetVertex( toVec3f(vertices[fans_v[1]]) );
v1.SetNormal( num_norms_is_num_verts ? normals[fans_n[1]] :
@@ -199,6 +209,8 @@
if (!fans_tc[1].empty()) {
v1.SetTexCoord( 1, getTexCoord(texCoords, fans_tc[1], tc1Scale, 1) );
}
+ v1.SetOverlayCoord(overlayCoords[fans_v[1]]);
+
for (unsigned i = 2; i < fans_v.size(); ++i) {
SGVertNormTex v2;
v2.SetVertex( toVec3f(vertices[fans_v[i]]) );
@@ -208,6 +220,8 @@
if (!fans_tc[1].empty()) {
v2.SetTexCoord( 1, getTexCoord(texCoords, fans_tc[1], tc1Scale, i) );
}
+ v2.SetOverlayCoord(overlayCoords[fans_v[i]]);
+
triangles.insert(v0, v1, v2);
v1 = v2;
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/simgear-2020.3.17/simgear/scene/tgdb/obj.cxx new/simgear-2020.3.18/simgear/scene/tgdb/obj.cxx
--- old/simgear-2020.3.17/simgear/scene/tgdb/obj.cxx 2022-11-20 19:01:30.000000000 +0100
+++ new/simgear-2020.3.18/simgear/scene/tgdb/obj.cxx 2023-03-14 08:49:42.000000000 +0100
@@ -26,10 +26,19 @@
# include
#endif
+#include
+#include
+#include
+#include
+#include
+
+
#include "obj.hxx"
#include
#include
+#include
+#include
#include "SGTileGeometryBin.hxx" // for original tile loading
#include "SGTileDetailsCallback.hxx" // for tile details ( random objects, and lighting )
@@ -54,6 +63,7 @@
double maxError = SG_SIMPLIFIER_MAX_ERROR;
double object_range = SG_OBJECT_RANGE_ROUGH;
double tile_min_expiry = SG_TILE_MIN_EXPIRY;
+ bool usePhotoscenery = false;
if (options) {
matlib = options->getMaterialLib();
@@ -69,6 +79,7 @@
maxError = propertyNode->getDoubleValue("/sim/rendering/terrain/simplifier/max-error", maxError);
object_range = propertyNode->getDoubleValue("/sim/rendering/static-lod/rough", object_range);
tile_min_expiry= propertyNode->getDoubleValue("/sim/rendering/plod-minimum-expiry-time-secs", tile_min_expiry);
+ usePhotoscenery = propertyNode->getBoolValue("/sim/rendering/photoscenery/enabled", usePhotoscenery);
}
SGVec3d center = tile.get_gbs_center();
@@ -77,12 +88,39 @@
if (matlib)
matcache = matlib->generateMatCache(geodPos);
+ std::vector<SGVec3d> nodes = tile.get_wgs84_nodes();
+
+ std::vector<SGVec2f> satellite_overlay_coords;
+ osg::ref_ptr<Orthophoto> orthophoto = nullptr;
+
+ if (usePhotoscenery) {
+ try {
+ const long index = lexical_cast<long>(osgDB::getSimpleFileName(osgDB::getNameLessExtension(path)));
+ orthophoto = OrthophotoManager::instance()->getOrthophoto(index);
+ } catch (bad_lexical_cast&) {
+ orthophoto = OrthophotoManager::instance()->getOrthophoto(nodes, center);
+ }
+ }
+
+
+
// rotate the tiles so that the bounding boxes get nearly axis aligned.
// this will help the collision tree's bounding boxes a bit ...
- std::vector<SGVec3d> nodes = tile.get_wgs84_nodes();
- for (unsigned i = 0; i < nodes.size(); ++i)
+ for (unsigned i = 0; i < nodes.size(); ++i) {
+ if (orthophoto) {
+ // Generate TexCoords for Overlay
+ const SGGeod node_geod = SGGeod::fromCart(nodes[i] + center);
+ const OrthophotoBounds actual_bbox = orthophoto->getBbox();
+ const SGVec2f coords = actual_bbox.getTexCoord(node_geod);
+ satellite_overlay_coords.push_back(coords);
+ } else {
+ satellite_overlay_coords.push_back(SGVec2f(0.0, 0.0));
+ }
+
nodes[i] = hlOr.transform(nodes[i]);
+ }
tile.set_wgs84_nodes(nodes);
+ tile.set_overlaycoords(satellite_overlay_coords);
SGQuatf hlOrf(hlOr[0], hlOr[1], hlOr[2], hlOr[3]);
std::vector<SGVec3f> normals = tile.get_normals();
@@ -97,6 +135,22 @@
return NULL;
osg::Node* node = tileGeometryBin->getSurfaceGeometry(matcache, useVBOs);
+ if (node) {
+ // Get base node stateset
+ osg::StateSet *stateSet = node->getOrCreateStateSet();
+
+ osg::ref_ptrosg::Uniform orthophotoAvailable = new osg::Uniform("orthophotoAvailable", false);
+ stateSet->addUniform(orthophotoAvailable, osg::StateAttribute::ON);
+
+ // Add satellite texture (if orthophoto exists)
+ if (usePhotoscenery && orthophoto) {
+ stateSet->setTextureAttributeAndModes(15, orthophoto->getTexture(), osg::StateAttribute::ON);
+ orthophotoAvailable->set(true);
+
+ SG_LOG(SG_OSG, SG_DEBUG, "Applying satellite orthophoto to terrain object with path " << path);
+ }
+ }
+
if (node && simplifyDistant) {
osgUtil::Simplifier simplifier(ratio, maxError, maxLength);
node->accept(simplifier);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/simgear-2020.3.17/simgear/scene/tgdb/obj.hxx new/simgear-2020.3.18/simgear/scene/tgdb/obj.hxx
--- old/simgear-2020.3.17/simgear/scene/tgdb/obj.hxx 2022-11-20 19:01:30.000000000 +0100
+++ new/simgear-2020.3.18/simgear/scene/tgdb/obj.hxx 2023-03-14 08:49:42.000000000 +0100
@@ -29,6 +29,8 @@
# error This library requires C++
#endif
+#include
+
#include
#include <string>
@@ -38,6 +40,9 @@
using std::string;
+using boost::lexical_cast;
+using boost::bad_lexical_cast;
+
class SGMaterialLib;
namespace simgear {
class SGReaderWriterOptions;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/simgear-2020.3.17/simgear/scene/util/CMakeLists.txt new/simgear-2020.3.18/simgear/scene/util/CMakeLists.txt
--- old/simgear-2020.3.17/simgear/scene/util/CMakeLists.txt 2022-11-20 19:01:30.000000000 +0100
+++ new/simgear-2020.3.18/simgear/scene/util/CMakeLists.txt 2023-03-14 08:49:42.000000000 +0100
@@ -7,6 +7,7 @@
NodeAndDrawableVisitor.hxx
Noise.hxx
OptionsReadFileCallback.hxx
+ OrthophotoManager.hxx
OsgDebug.hxx
OsgMath.hxx
OsgSingleton.hxx
@@ -41,6 +42,7 @@
NodeAndDrawableVisitor.cxx
Noise.cxx
OptionsReadFileCallback.cxx
+ OrthophotoManager.cxx
OsgDebug.cxx
parse_color.cxx
PrimitiveUtils.cxx
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/simgear-2020.3.17/simgear/scene/util/OrthophotoManager.cxx new/simgear-2020.3.18/simgear/scene/util/OrthophotoManager.cxx
--- old/simgear-2020.3.17/simgear/scene/util/OrthophotoManager.cxx 1970-01-01 01:00:00.000000000 +0100
+++ new/simgear-2020.3.18/simgear/scene/util/OrthophotoManager.cxx 2023-03-14 08:49:42.000000000 +0100
@@ -0,0 +1,402 @@
+// OrthophotoManager.cxx -- manages satellite orthophotos
+//
+// Copyright (C) 2020 Nathaniel MacArthur-Warner nathanielwarner77@gmail.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 Library General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+#include "OrthophotoManager.hxx"
+#include "SGSceneFeatures.hxx"
+#include
+
+namespace simgear {
+
+ OrthophotoBounds OrthophotoBounds::fromBucket(const SGBucket& bucket) {
+ OrthophotoBounds bounds;
+ bounds.expandToInclude(bucket);
+ return bounds;
+ }
+
+ void OrthophotoBounds::_updateHemisphere() {
+ if (_minPosLon <= 180 && _maxPosLon >= 0 && _minNegLon < 0 && _maxNegLon >= -180) {
+ // We have negative and positive longitudes.
+ // Choose whether we're straddling the Prime Meridian or 180th meridian
+ if (_maxPosLon - _minNegLon < 180) {
+ _hemisphere = StraddlingPm;
+ } else {
+ _hemisphere = StraddlingIdl;
+ }
+ }
+ else if (_minPosLon <= 180.0 && _maxPosLon >= 0.0) {
+ _hemisphere = Eastern;
+ }
+ else if (_minNegLon < 0.0 && _maxNegLon >= -180.0) {
+ _hemisphere = Western;
+ }
+ else {
+ _hemisphere = Invalid;
+ }
+ }
+
+ double OrthophotoBounds::getWidth() const {
+ switch (_hemisphere) {
+ case Eastern:
+ return _maxPosLon - _minPosLon;
+ case Western:
+ return _maxNegLon - _minNegLon;
+ case StraddlingPm:
+ return _maxPosLon - _minNegLon;
+ case StraddlingIdl:
+ return (180.0 - _minPosLon) + (_maxNegLon + 180.0);
+ default:
+ SG_LOG(SG_TERRAIN, SG_ALERT, "OrthophotoBounds::getWidth: My data is invalid. Returning 0.");
+ return 0.0;
+ }
+ }
+
+ double OrthophotoBounds::getHeight() const {
+ return _maxLat - _minLat;
+ }
+
+ SGVec2f OrthophotoBounds::getTexCoord(const SGGeod& geod) const {
+
+ const double lon = geod.getLongitudeDeg();
+ const double width = getWidth();
+ float x = 0.0;
+
+ switch (_hemisphere) {
+ case Eastern:
+ x = (lon - _minPosLon) / width;
+ break;
+ case Western:
+ x = (lon - _minNegLon) / width;
+ break;
+ case StraddlingPm:
+ x = (lon - _minNegLon) / width;
+ break;
+ case StraddlingIdl:
+ if (lon >= 0) {
+ // Geod is in the eastern hemisphere
+ x = (lon - _minPosLon) / width;
+ } else {
+ // Geod is in the western hemisphere
+ x = (180.0 - _minPosLon + lon) / width;
+ }
+ break;
+ default:
+ SG_LOG(SG_TERRAIN, SG_ALERT, "OrthophotoBounds::getTexCoord: My data is invalid.");
+ break;
+ }
+
+ const float y = (_maxLat - geod.getLatitudeDeg()) / getHeight();
+
+ return SGVec2f(x, y);
+ }
+
+ double OrthophotoBounds::getLonOffset(const OrthophotoBounds& other) const {
+
+ std::string error_message = "";
+
+ switch (_hemisphere) {
+ case Eastern:
+ if (other._hemisphere == Eastern)
+ return other._minPosLon - _minPosLon;
+ else
+ error_message = "I'm not in the same hemisphere as other.";
+ break;
+ case Western:
+ if (other._hemisphere == Western)
+ return other._minNegLon - _minNegLon;
+ else
+ error_message = "I'm not in the same hemisphere as other.";
+ break;
+ case StraddlingPm:
+ if (other._hemisphere == Western || other._hemisphere == StraddlingPm)
+ return other._minNegLon - _minNegLon;
+ else if (other._hemisphere == Eastern)
+ return -_minNegLon + other._minPosLon;
+ else
+ error_message = "I'm not in the same hemisphere as other";
+ break;
+ case StraddlingIdl:
+ if (other._hemisphere == Eastern || other._hemisphere == StraddlingIdl) {
+ return other._minPosLon - _minPosLon;
+ } else if (other._hemisphere == StraddlingIdl) {
+ return (180.0 - _minPosLon) + (other._minNegLon + 180.0);
+ } else {
+ error_message = "Other has invalid data.";
+ }
+ break;
+ default:
+ error_message = "My data is invalid.";
+ break;
+ }
+
+ SG_LOG(SG_TERRAIN, SG_ALERT, "OrthophotoBounds::getLonOffset: " << error_message << " Returning 0.");
+ return 0.0;
+ }
+
+ double OrthophotoBounds::getLatOffset(const OrthophotoBounds& other) const {
+ return _maxLat - other._maxLat;
+ }
+
+ void OrthophotoBounds::expandToInclude(const SGBucket& bucket) {
+ double center_lon = bucket.get_center_lon();
+ double center_lat = bucket.get_center_lat();
+ double width = bucket.get_width();
+ double height = bucket.get_height();
+
+ double left = center_lon - width / 2;
+ double right = center_lon + width / 2;
+ double bottom = center_lat - height / 2;
+ double top = center_lat + height / 2;
+
+ expandToInclude(left, bottom);
+ expandToInclude(right, top);
+ }
+
+ void OrthophotoBounds::expandToInclude(const double lon, const double lat) {
+ if (lon >= 0) {
+ if (lon < _minPosLon)
+ _minPosLon = lon;
+ if (lon > _maxPosLon)
+ _maxPosLon = lon;
+ } else {
+ if (lon < _minNegLon)
+ _minNegLon = lon;
+ if (lon > _maxNegLon)
+ _maxNegLon = lon;
+ }
+
+ if (lat < _minLat)
+ _minLat = lat;
+ if (lat > _maxLat)
+ _maxLat = lat;
+
+ _updateHemisphere();
+ }
+
+ void OrthophotoBounds::expandToInclude(const OrthophotoBounds& bounds) {
+ switch (bounds._hemisphere) {
+ case Eastern:
+ expandToInclude(bounds._minPosLon, bounds._minLat);
+ expandToInclude(bounds._maxPosLon, bounds._maxLat);
+ break;
+ case Western:
+ expandToInclude(bounds._minNegLon, bounds._minLat);
+ expandToInclude(bounds._maxNegLon, bounds._maxLat);
+ break;
+ case StraddlingPm:
+ expandToInclude(bounds._minNegLon, bounds._minLat);
+ expandToInclude(bounds._maxPosLon, bounds._maxLat);
+ break;
+ case StraddlingIdl:
+ expandToInclude(bounds._minPosLon, bounds._minLat);
+ expandToInclude(bounds._maxNegLon, bounds._maxLat);
+ break;
+ case Invalid:
+ SG_LOG(SG_TERRAIN, SG_ALERT, "OrthophotoBounds::absorb: Data in bounds to absorb is invalid. Aborting.");
+ break;
+ }
+ }
+
+ Texture2DRef textureFromImage(const ImageRef& image) {
+ Texture2DRef texture = new osg::Texture2D(image);
+ texture->setWrap(osg::Texture::WrapParameter::WRAP_S, osg::Texture::WrapMode::CLAMP_TO_EDGE);
+ texture->setWrap(osg::Texture::WrapParameter::WRAP_T, osg::Texture::WrapMode::CLAMP_TO_EDGE);
+ texture->setWrap(osg::Texture::WrapParameter::WRAP_R, osg::Texture::WrapMode::CLAMP_TO_EDGE);
+ texture->setMaxAnisotropy(SGSceneFeatures::instance()->getTextureFilter());
+ return texture;
+ }
+
+ OrthophotoRef Orthophoto::fromBucket(const SGBucket& bucket, const PathList& scenery_paths) {
+
+ const std::string bucket_path = bucket.gen_base_path();
+
+ for (const auto& scenery_path : scenery_paths) {
+ SGPath path = scenery_path / "Orthophotos" / bucket_path / std::to_string(bucket.gen_index());
+
+ SGPath dds_path = path;
+ dds_path.concat(".dds");
+ if (dds_path.exists()) {
+ ImageRef image = osgDB::readRefImageFile(dds_path.str());
+ if (image) {
+ if (!image->isCompressed()) {
+ SG_LOG(SG_OSG, SG_WARN, "Loading uncompressed DDS orthophoto. This is known to cause problems on some systems.");
+ }
+ const Texture2DRef texture = textureFromImage(image);
+ const OrthophotoBounds bbox = OrthophotoBounds::fromBucket(bucket);
+ return new Orthophoto(texture, bbox);
+ }
+ }
+
+ SGPath png_path = path;
+ png_path.concat(".png");
+ if (png_path.exists()) {
+ ImageRef image = osgDB::readRefImageFile(png_path.str());
+ if (image) {
+ image->flipVertical();
+ const Texture2DRef texture = textureFromImage(image);
+ const OrthophotoBounds bbox = OrthophotoBounds::fromBucket(bucket);
+ return new Orthophoto(texture, bbox);
+ }
+ }
+ }
+
+ return nullptr;
+ }
+
+ Orthophoto::Orthophoto(const std::vector<OrthophotoRef>& orthophotos) {
+
+ for (const auto& orthophoto : orthophotos) {
+ _bbox.expandToInclude(orthophoto->getBbox());
+ }
+
+ const OrthophotoRef& some_orthophoto = orthophotos[0];
+ const ImageRef& some_image = some_orthophoto->_texture->getImage();
+ const OrthophotoBounds& some_bbox = some_orthophoto->getBbox();
+ const double degs_to_pixels_x = some_image->s() / some_bbox.getWidth();
+ const double degs_to_pixels_y = some_image->t() / some_bbox.getHeight();
+
+ const int total_width = degs_to_pixels_x * _bbox.getWidth();
+ const int total_height = degs_to_pixels_y * _bbox.getHeight();
+
+ const int depth = some_image->r();
+ GLenum pixel_format = some_image->getPixelFormat();
+ GLenum data_type = some_image->getDataType();
+ int packing = some_image->getPacking();
+
+ ImageRef composite_image = new osg::Image();
+ composite_image->allocateImage(total_width, total_height, depth, pixel_format, data_type, packing);
+
+ for (const auto& orthophoto : orthophotos) {
+
+ const OrthophotoBounds& bounds = orthophoto->getBbox();
+ const int width = degs_to_pixels_x * bounds.getWidth();
+ const int height = degs_to_pixels_y * bounds.getHeight();
+ const int s_offset = degs_to_pixels_x * _bbox.getLonOffset(bounds);
+ const int t_offset = degs_to_pixels_y * _bbox.getLatOffset(bounds);
+
+ ImageRef sub_image = orthophoto->_texture->getImage();
+
+ if (sub_image->s() != width || sub_image->t() != height) {
+ SG_LOG(SG_OSG, SG_INFO, "Orthophoto resolution mismatch. Automatic scaling will be performed.");
+ ImageRef scaled_image;
+ bool success = ImageUtils::resizeImage(sub_image, width, height, scaled_image);
+ if (success) {
+ sub_image = scaled_image;
+ } else {
+ SG_LOG(SG_OSG, SG_ALERT, "Failed to scale part of composite orthophoto. The image on the airport may be distorted.");
+ }
+ }
+
+ if (sub_image->getPixelFormat() != pixel_format || sub_image->getDataType() != data_type) {
+ SG_LOG(SG_OSG, SG_INFO, "Pixel format or data type mismatch. Attempting to convert component of composite orthophoto.");
+ if (ImageUtils::canConvert(sub_image, pixel_format, data_type)) {
+ sub_image = ImageUtils::convert(sub_image, pixel_format, data_type);
+ } else {
+ SG_LOG(SG_OSG, SG_ALERT, "Failed to convert component of composite orthophoto. Part of the image on the airport may be missing.");
+ }
+ }
+
+ composite_image->copySubImage(s_offset, t_offset, 0, sub_image);
+ }
+
+ int max_texture_size = SGSceneFeatures::instance()->getMaxTextureSize();
+ int new_width = total_width;
+ int new_height = total_height;
+ if (new_width > max_texture_size) {
+ int factor = new_width / max_texture_size;
+ new_width /= factor;
+ new_height /= factor;
+ }
+ if (new_height > max_texture_size) {
+ int factor = new_height / max_texture_size;
+ new_width /= factor;
+ new_height /= factor;
+ }
+ if (total_width != new_width || total_height != new_height) {
+ SG_LOG(SG_OSG, SG_INFO, "Composite orthophoto exceeds the maximum texture size of your GPU. Automatic scaling will be performed.");
+ ImageRef scaled_image;
+ bool success = ImageUtils::resizeImage(composite_image, new_width, new_height, scaled_image);
+ if (success) {
+ composite_image = scaled_image;
+ } else {
+ SG_LOG(SG_OSG, SG_ALERT, "Failed to scale composite orthophoto. You may encounter errors due to the oversize texture.");
+ }
+ }
+
+ _texture = textureFromImage(composite_image);
+ }
+
+ OrthophotoManager* OrthophotoManager::instance() {
+ return SingletonRefPtr<OrthophotoManager>::instance();
+ }
+
+ void OrthophotoManager::registerOrthophoto(const long bucket_idx, const OrthophotoRef& orthophoto) {
+ OrthophotoWeakRef& entry = _orthophotos[bucket_idx];
+
+ if (entry.valid()) {
+ SG_LOG(SG_TERRAIN, SG_WARN, "OrthophotoManager::registerOrthophoto(): Bucket index " << bucket_idx << " already has a registered orthophoto.");
+ }
+
+ if (!orthophoto) {
+ SG_LOG(SG_TERRAIN, SG_WARN, "OrthophotoManager::registerOrthophoto(): Registering null orthophoto for bucket index " << bucket_idx);
+ }
+
+ entry = orthophoto;
+
+ SG_LOG(SG_TERRAIN, SG_INFO, "Registered orthophoto for bucket index " << bucket_idx);
+ }
+
+ OrthophotoRef OrthophotoManager::getOrthophoto(const long bucket_idx) {
+ OrthophotoWeakRef weak_ref = _orthophotos[bucket_idx];
+ OrthophotoRef ref;
+ if (weak_ref.valid()) {
+ weak_ref.lock(ref);
+ }
+ return ref;
+ }
+
+ OrthophotoRef OrthophotoManager::getOrthophoto(const std::vector<SGVec3d>& nodes, const SGVec3d& center) {
+
+ std::unordered_map orthophotos_attempted;
+ std::vector<OrthophotoRef> orthophotos;
+ OrthophotoBounds needed_bounds;
+
+ for (const auto& node : nodes) {
+ const SGGeod node_geod = SGGeod::fromCart(node + center);
+ needed_bounds.expandToInclude(node_geod.getLongitudeDeg(), node_geod.getLatitudeDeg());
+ const SGBucket bucket(node_geod);
+ const long bucket_idx = bucket.gen_index();
+ bool& orthophoto_attempted = orthophotos_attempted[bucket_idx];
+ if (!orthophoto_attempted) {
+ OrthophotoRef orthophoto = this->getOrthophoto(bucket_idx);
+ if (orthophoto) {
+ orthophotos.push_back(orthophoto);
+ }
+ orthophoto_attempted = true;
+ }
+ }
+
+ if (orthophotos.empty()) {
+ return nullptr;
+ } else if (orthophotos.size() == 1) {
+ return orthophotos[0];
+ } else {
+ return new Orthophoto(orthophotos);
+ }
+ }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/simgear-2020.3.17/simgear/scene/util/OrthophotoManager.hxx new/simgear-2020.3.18/simgear/scene/util/OrthophotoManager.hxx
--- old/simgear-2020.3.17/simgear/scene/util/OrthophotoManager.hxx 1970-01-01 01:00:00.000000000 +0100
+++ new/simgear-2020.3.18/simgear/scene/util/OrthophotoManager.hxx 2023-03-14 08:49:42.000000000 +0100
@@ -0,0 +1,112 @@
+// OrthophotoManager.hxx -- manages satellite orthophotos
+//
+// Copyright (C) 2020 Nathaniel MacArthur-Warner nathanielwarner77@gmail.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 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_SCENE_ORTHOPHOTO_MANAGER
+#define SG_SCENE_ORTHOPHOTO_MANAGER
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "SGSceneFeatures.hxx"
+#include "OsgSingleton.hxx"
+#include "SGImageUtils.hxx"
+
+namespace simgear {
+
+ using ImageRef = osg::ref_ptrosg::Image;
+ using Texture2DRef = osg::ref_ptrosg::Texture2D;
+
+ class Orthophoto;
+ using OrthophotoRef = osg::ref_ptr<Orthophoto>;
+ using OrthophotoWeakRef = osg::observer_ptr<Orthophoto>;
+
+ class OrthophotoBounds {
+ private:
+ double _minNegLon = SGLimitsd::max();
+ double _minPosLon = SGLimitsd::max();
+ double _maxNegLon = SGLimitsd::lowest();
+ double _maxPosLon = SGLimitsd::lowest();
+ double _minLat = SGLimitsd::max();
+ double _maxLat = SGLimitsd::lowest();
+
+ enum Hemisphere {Eastern, Western, StraddlingPm, StraddlingIdl, Invalid} _hemisphere = Invalid;
+ void _updateHemisphere();
+
+ public:
+ static OrthophotoBounds fromBucket(const SGBucket& bucket);
+
+ double getWidth() const;
+ double getHeight() const;
+ SGVec2f getTexCoord(const SGGeod& geod) const;
+ double getLonOffset(const OrthophotoBounds& other) const;
+ double getLatOffset(const OrthophotoBounds& other) const;
+
+ void expandToInclude(const SGBucket& bucket);
+ void expandToInclude(const double lon, const double lat);
+ void expandToInclude(const OrthophotoBounds& bounds);
+ };
+
+ class Orthophoto : public osg::Referenced {
+ private:
+ Texture2DRef _texture;
+ OrthophotoBounds _bbox;
+
+ public:
+ static OrthophotoRef fromBucket(const SGBucket& bucket, const PathList& scenery_paths);
+
+ Orthophoto(const Texture2DRef& texture, const OrthophotoBounds& bbox) { _texture = texture; _bbox = bbox; }
+ Orthophoto(const std::vector<OrthophotoRef>& orthophotos);
+
+ Texture2DRef getTexture() const { return _texture; };
+ OrthophotoBounds getBbox() const { return _bbox; };
+ };
+
+ class OrthophotoManager : public osg::Referenced {
+ private:
+ std::unordered_map _orthophotos;
+ public:
+ static OrthophotoManager* instance();
+
+ void registerOrthophoto(const long bucket_idx, const OrthophotoRef& orthophoto);
+
+ /**
+ * Get an orthophoto by bucket index
+ **/
+ OrthophotoRef getOrthophoto(const long bucket_idx);
+
+ /**
+ * Get an orthophoto given a set of nodes.
+ * Used for airports, since they are not buckets.
+ **/
+ OrthophotoRef getOrthophoto(const std::vector<SGVec3d>& nodes, const SGVec3d& center);
+ };
+}
+
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/simgear-2020.3.17/simgear-version new/simgear-2020.3.18/simgear-version
--- old/simgear-2020.3.17/simgear-version 2022-11-20 19:01:30.000000000 +0100
+++ new/simgear-2020.3.18/simgear-version 2023-03-14 08:49:42.000000000 +0100
@@ -1 +1 @@
-2020.3.17
+2020.3.18