Merge /p/flightgear-photoscenery/simgear/ branch next-photoscenery-r6 into next

https://sourceforge.net/p/flightgear/simgear/merge-requests/88/
This commit is contained in:
xDraconian 2020-12-12 23:13:37 +00:00
commit b9c39fd2ab
2 changed files with 55 additions and 97 deletions

View File

@ -209,6 +209,15 @@ namespace simgear {
} }
} }
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) { OrthophotoRef Orthophoto::fromBucket(const SGBucket& bucket, const PathList& scenery_paths) {
const std::string bucket_path = bucket.gen_base_path(); const std::string bucket_path = bucket.gen_base_path();
@ -216,133 +225,79 @@ namespace simgear {
for (const auto& scenery_path : scenery_paths) { for (const auto& scenery_path : scenery_paths) {
SGPath path = scenery_path / "Orthophotos" / bucket_path / std::to_string(bucket.gen_index()); SGPath path = scenery_path / "Orthophotos" / bucket_path / std::to_string(bucket.gen_index());
path.concat(".png"); SGPath dds_path = path;
if (path.exists()) { dds_path.concat(".dds");
ImageRef image = osgDB::readRefImageFile(path.str()); if (dds_path.exists()) {
ImageRef image = osgDB::readRefImageFile(dds_path.str());
if (!image) {
return nullptr;
}
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) { if (!image) {
return nullptr; return nullptr;
} }
image->flipVertical(); image->flipVertical();
OrthophotoBounds bbox = OrthophotoBounds::fromBucket(bucket); const Texture2DRef texture = textureFromImage(image);
return new Orthophoto(image, bbox); const OrthophotoBounds bbox = OrthophotoBounds::fromBucket(bucket);
return new Orthophoto(texture, bbox);
} }
} }
return nullptr; return nullptr;
} }
// Handy image cropping function from osgEarth Orthophoto::Orthophoto(const std::vector<OrthophotoRef>& orthophotos) {
osg::Image* cropImage(const osg::Image* image,
double src_minx, double src_miny, double src_maxx, double src_maxy,
double &dst_minx, double &dst_miny, double &dst_maxx, double &dst_maxy) {
if ( image == 0L )
return 0L;
//Compute the desired cropping rectangle
int windowX = osg::clampBetween( (int)floor( (dst_minx - src_minx) / (src_maxx - src_minx) * (double)image->s()), 0, image->s()-1);
int windowY = osg::clampBetween( (int)floor( (dst_miny - src_miny) / (src_maxy - src_miny) * (double)image->t()), 0, image->t()-1);
int windowWidth = osg::clampBetween( (int)ceil( (dst_maxx - src_minx) / (src_maxx - src_minx) * (double)image->s()) - windowX, 0, image->s());
int windowHeight = osg::clampBetween( (int)ceil( (dst_maxy - src_miny) / (src_maxy - src_miny) * (double)image->t()) - windowY, 0, image->t());
if (windowX + windowWidth > image->s())
{
windowWidth = image->s() - windowX;
}
if (windowY + windowHeight > image->t())
{
windowHeight = image->t() - windowY;
}
if ((windowWidth * windowHeight) == 0)
{
return NULL;
}
//Compute the actual bounds of the area we are computing
double res_s = (src_maxx - src_minx) / (double)image->s();
double res_t = (src_maxy - src_miny) / (double)image->t();
dst_minx = src_minx + (double)windowX * res_s;
dst_miny = src_miny + (double)windowY * res_t;
dst_maxx = dst_minx + (double)windowWidth * res_s;
dst_maxy = dst_miny + (double)windowHeight * res_t;
//OE_NOTICE << "Copying from " << windowX << ", " << windowY << ", " << windowWidth << ", " << windowHeight << std::endl;
//Allocate the croppped image
osg::Image* cropped = new osg::Image;
cropped->allocateImage(windowWidth, windowHeight, image->r(), image->getPixelFormat(), image->getDataType());
cropped->setInternalTextureFormat( image->getInternalTextureFormat() );
for (int layer=0; layer<image->r(); ++layer)
{
for (int src_row = windowY, dst_row=0; dst_row < windowHeight; src_row++, dst_row++)
{
if (src_row > image->t()-1) SG_LOG(SG_OSG, SG_INFO, "HeightBroke");
const void* src_data = image->data(windowX, src_row, layer);
void* dst_data = cropped->data(0, dst_row, layer);
memcpy( dst_data, src_data, cropped->getRowSizeInBytes());
}
}
return cropped;
}
Orthophoto::Orthophoto(const std::vector<OrthophotoRef>& orthophotos, const OrthophotoBounds& needed_bbox) {
OrthophotoBounds prelim_bbox;
for (const auto& orthophoto : orthophotos) { for (const auto& orthophoto : orthophotos) {
prelim_bbox.expandToInclude(orthophoto->getBbox()); _bbox.expandToInclude(orthophoto->getBbox());
} }
const OrthophotoRef& some_orthophoto = orthophotos[0]; const OrthophotoRef& some_orthophoto = orthophotos[0];
const ImageRef& some_image = some_orthophoto->_image; const ImageRef& some_image = some_orthophoto->_texture->getImage();
const OrthophotoBounds& some_bbox = some_orthophoto->getBbox(); const OrthophotoBounds& some_bbox = some_orthophoto->getBbox();
const double degs_to_pixels = some_image->s() / some_bbox.getWidth(); const double degs_to_pixels = some_image->s() / some_bbox.getWidth();
const int total_width = degs_to_pixels * prelim_bbox.getWidth(); const int total_width = degs_to_pixels * _bbox.getWidth();
const int total_height = degs_to_pixels * prelim_bbox.getHeight(); const int total_height = degs_to_pixels * _bbox.getHeight();
const int depth = some_image->r(); const int depth = some_image->r();
GLenum pixel_format = some_image->getPixelFormat(); GLenum pixel_format = some_image->getPixelFormat();
GLenum data_type = some_image->getDataType(); GLenum data_type = some_image->getDataType();
int packing = some_image->getPacking(); int packing = some_image->getPacking();
ImageRef prelim_image = new osg::Image(); ImageRef composite_image = new osg::Image();
prelim_image->allocateImage(total_width, total_height, depth, pixel_format, data_type, packing); composite_image->allocateImage(total_width, total_height, depth, pixel_format, data_type, packing);
for (const auto& orthophoto : orthophotos) { for (const auto& orthophoto : orthophotos) {
const OrthophotoBounds& bounds = orthophoto->getBbox(); const OrthophotoBounds& bounds = orthophoto->getBbox();
const int width = degs_to_pixels * bounds.getWidth(); const int width = degs_to_pixels * bounds.getWidth();
const int height = degs_to_pixels * bounds.getHeight(); const int height = degs_to_pixels * bounds.getHeight();
const int s_offset = degs_to_pixels * prelim_bbox.getLonOffset(bounds); const int s_offset = degs_to_pixels * _bbox.getLonOffset(bounds);
const int t_offset = degs_to_pixels * prelim_bbox.getLatOffset(bounds); const int t_offset = degs_to_pixels * _bbox.getLatOffset(bounds);
// Make a deep copy of the orthophoto's image so that we don't modify the original when scaling // Make a deep copy of the orthophoto's image so that we don't modify the original when scaling
ImageRef sub_image = new osg::Image(*orthophoto->_image, osg::CopyOp::DEEP_COPY_ALL); ImageRef sub_image = new osg::Image(*orthophoto->_texture->getImage(), osg::CopyOp::DEEP_COPY_ALL);
if (sub_image->getPixelFormat() != pixel_format) {
SG_LOG(SG_OSG, SG_ALERT, "Pixel format mismatch. Not creating part of composite orthophoto.");
continue;
}
sub_image->scaleImage(width, height, depth); sub_image->scaleImage(width, height, depth);
prelim_image->copySubImage(s_offset, t_offset, 0, sub_image); composite_image->copySubImage(s_offset, t_offset, 0, sub_image);
} }
double x_min = prelim_bbox.getLonOffset(needed_bbox) * degs_to_pixels; _texture = textureFromImage(composite_image);
double y_min = prelim_bbox.getLatOffset(needed_bbox) * degs_to_pixels;
double x_max = x_min + needed_bbox.getWidth() * degs_to_pixels;
double y_max = y_min + needed_bbox.getHeight() * degs_to_pixels;
_image = cropImage(prelim_image, 0.0, 0.0, total_width, total_height, x_min, y_min, x_max, y_max);
_bbox = needed_bbox; // Theoretically, it would be good to adjust from how the bounds have changed from cropping
}
osg::ref_ptr<osg::Texture2D> Orthophoto::getTexture() {
osg::ref_ptr<osg::Texture2D> 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;
} }
OrthophotoManager* OrthophotoManager::instance() { OrthophotoManager* OrthophotoManager::instance() {
@ -397,8 +352,10 @@ namespace simgear {
if (orthophotos.size() == 0) { if (orthophotos.size() == 0) {
return nullptr; return nullptr;
} else if (orthophotos.size() == 1) {
return orthophotos[0];
} else {
return new Orthophoto(orthophotos);
} }
return new Orthophoto(orthophotos, needed_bounds);
} }
} }

View File

@ -40,6 +40,7 @@
namespace simgear { namespace simgear {
using ImageRef = osg::ref_ptr<osg::Image>; using ImageRef = osg::ref_ptr<osg::Image>;
using Texture2DRef = osg::ref_ptr<osg::Texture2D>;
class Orthophoto; class Orthophoto;
using OrthophotoRef = osg::ref_ptr<Orthophoto>; using OrthophotoRef = osg::ref_ptr<Orthophoto>;
@ -73,16 +74,16 @@ namespace simgear {
class Orthophoto : public osg::Referenced { class Orthophoto : public osg::Referenced {
private: private:
ImageRef _image; Texture2DRef _texture;
OrthophotoBounds _bbox; OrthophotoBounds _bbox;
public: public:
static OrthophotoRef fromBucket(const SGBucket& bucket, const PathList& scenery_paths); static OrthophotoRef fromBucket(const SGBucket& bucket, const PathList& scenery_paths);
Orthophoto(const ImageRef& image, const OrthophotoBounds& bbox) { _image = image; _bbox = bbox; } Orthophoto(const Texture2DRef& texture, const OrthophotoBounds& bbox) { _texture = texture; _bbox = bbox; }
Orthophoto(const std::vector<OrthophotoRef>& orthophotos, const OrthophotoBounds& needed_bbox); Orthophoto(const std::vector<OrthophotoRef>& orthophotos);
osg::ref_ptr<osg::Texture2D> getTexture(); Texture2DRef getTexture() const { return _texture; };
OrthophotoBounds getBbox() const { return _bbox; }; OrthophotoBounds getBbox() const { return _bbox; };
}; };