Skip to content

Commit

Permalink
Retrofit ImageLayer and LifeMapLayer with the applyPostLayer idiom th…
Browse files Browse the repository at this point in the history
…at supports coverages
  • Loading branch information
gwaldron committed Mar 27, 2024
1 parent a301335 commit d3c0ced
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 72 deletions.
14 changes: 8 additions & 6 deletions src/osgEarth/ImageLayer
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/

#ifndef OSGEARTH_IMAGE_TERRAIN_LAYER_H
#define OSGEARTH_IMAGE_TERRAIN_LAYER_H 1
#pragma once

#include <osgEarth/Common>
#include <osgEarth/Config>
Expand Down Expand Up @@ -253,6 +251,13 @@ namespace osgEarth
//! using a createImage driver
void setUseCreateTexture();

//! Apply a post-processing layers to the image
virtual GeoImage applyPostLayer(
const GeoImage& image,
const TileKey& key,
Layer* postLayer,
ProgressCallback* progress) const;

osg::ref_ptr<osg::Image> _emptyImage;

private:
Expand Down Expand Up @@ -333,6 +338,3 @@ namespace osgEarth
} // namespace osgEarth

OSGEARTH_SPECIALIZE_CONFIG(osgEarth::ImageLayer::Options);


#endif // OSGEARTH_IMAGE_TERRAIN_LAYER_H
79 changes: 21 additions & 58 deletions src/osgEarth/ImageLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,17 +362,14 @@ ImageLayer::getColorFilters() const
}

GeoImage
ImageLayer::createImage(
const TileKey& key)
ImageLayer::createImage(const TileKey& key)
{
return createImage(key, nullptr);
}

GeoImage
ImageLayer::createImage(
const TileKey& key,
ProgressCallback* progress)
{
ImageLayer::createImage(const TileKey& key, ProgressCallback* progress)
{
OE_PROFILING_ZONE;
OE_PROFILING_ZONE_TEXT(getName() + " " + key.str());

Expand All @@ -383,21 +380,23 @@ ImageLayer::createImage(

NetworkMonitor::ScopedRequestLayer layerRequest(getName());

GeoImage result = createImageInKeyProfile( key, progress );
GeoImage result = createImageInKeyProfile(key, progress);

// Post-cache operations:

if (!_postLayers.empty())
{
for (auto& post : _postLayers)
{
// if we didn't get a result from the actual key, try to fall back
// so we can apply the post to "something".
if (!result.valid())
{
TileKey bestKey = getBestAvailableTileKey(key);
result = createImageInKeyProfile(bestKey, progress);
}

result = post->createImage(result, key, progress);
result = applyPostLayer(result, key, post.get(), progress);
}
}

Expand All @@ -410,39 +409,22 @@ ImageLayer::createImage(
}

GeoImage
ImageLayer::createImage(
const GeoImage& canvas,
const TileKey& key,
ProgressCallback* progress)
ImageLayer::applyPostLayer(const GeoImage& canvas, const TileKey& key, Layer* post, ProgressCallback* progress) const
{
Threading::ScopedReadLock lock(layerMutex());
return createImageImplementation(canvas, key, progress);
}

struct Hooks
{
static void put(osgDB::Options* read_options, std::shared_ptr<Hooks> hooks)
{
ObjectStorage::set(read_options, hooks);
}

static std::shared_ptr<Hooks> get(const osgDB::Options* read_options)
auto post_imageLayer = dynamic_cast<ImageLayer*>(post);
if (post_imageLayer)
{
std::shared_ptr<Hooks> hooks;
ObjectStorage::get(read_options, hooks);
return hooks;
}

ReadResult pre_read(Layer* layer, const TileKey& key, ProgressCallback* progress)
{
return ReadResult(ReadResult::RESULT_OK);
return post_imageLayer->createImage(canvas, key, progress);
}
else return canvas;
}

ReadResult post_read(Layer* layer, const TileKey& key, const GeoImage& data, ProgressCallback* progress)
{
return ReadResult(ReadResult::RESULT_OK);
}
};
GeoImage
ImageLayer::createImage(const GeoImage& canvas, const TileKey& key, ProgressCallback* progress)
{
Threading::ScopedReadLock lock(layerMutex());
return createImageImplementation(canvas, key, progress);
}

GeoImage
ImageLayer::createImageInKeyProfile(const TileKey& key, ProgressCallback* progress)
Expand Down Expand Up @@ -470,21 +452,6 @@ ImageLayer::createImageInKeyProfile(const TileKey& key, ProgressCallback* progre

GeoImage result;

#if HOOKS
auto hooks = Hooks::get(getReadOptions());
if (hooks)
{
auto rr = hooks->pre_read(this, key, progress);
auto image = rr.releaseImage();
auto status = hooks->prehook_image(this, key, progress, result);
if (status.isError())
return GeoImage(status);
else if (result.valid())
return result;
}
#endif

#if 1
OE_DEBUG << LC << "create image for \"" << key.str() << "\", ext= "
<< key.getExtent().toString() << std::endl;

Expand Down Expand Up @@ -561,7 +528,6 @@ ImageLayer::createImageInKeyProfile(const TileKey& key, ProgressCallback* progre
return GeoImage::INVALID;
}
}
#endif

if (key.getProfile()->isHorizEquivalentTo(getProfile()))
{
Expand Down Expand Up @@ -891,7 +857,7 @@ ImageLayer::removeCallback(ImageLayer::Callback* c)
}

void
ImageLayer::addPostLayer(ImageLayer* layer)
ImageLayer::addPostLayer(Layer* layer)
{
std::lock_guard<std::mutex> lock(_postLayers.mutex());
_postLayers.push_back(layer);
Expand All @@ -902,10 +868,7 @@ ImageLayer::addPostLayer(ImageLayer* layer)
#define ARENA_ASYNC_LAYER "oe.rex.loadtile"
//#define FUTURE_IMAGE_COLOR_PLACEHOLDER

FutureTexture2D::FutureTexture2D(
ImageLayer* layer,
const TileKey& key) :

FutureTexture2D::FutureTexture2D(ImageLayer* layer, const TileKey& key) :
osg::Texture2D(),
FutureTexture(),
_layer(layer),
Expand Down
11 changes: 3 additions & 8 deletions src/osgEarthProcedural/LifeMapLayer
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#ifndef OSGEARTH_PROCEDURAL_LIFE_MAP_LAYER_H
#define OSGEARTH_PROCEDURAL_LIFE_MAP_LAYER_H
#pragma once

#include <osgEarthProcedural/Export>
#include <osgEarthProcedural/BiomeLayer>
Expand Down Expand Up @@ -113,14 +112,12 @@ namespace osgEarth { namespace Procedural

public:

virtual void addedToMap(const Map* map) override;
void addedToMap(const Map* map) override;

virtual void removedFromMap(const Map* map) override;
void removedFromMap(const Map* map) override;

protected:

virtual ~LifeMapLayer() { }

osg::observer_ptr<const Map> _map;
mutable ElevationPool::WorkingSet _workingSet;
osg::ref_ptr<osg::Image> _noiseFunc;
Expand All @@ -133,5 +130,3 @@ namespace osgEarth { namespace Procedural
};

} } // namespace osgEarth::Procedural

#endif // OSGEARTH_PROCEDURAL_LIFE_MAP_LAYER_H
78 changes: 78 additions & 0 deletions src/osgEarthProcedural/LifeMapLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -888,3 +888,81 @@ LifeMapLayer::createImageImplementation(

return std::move(result);
}

GeoImage
LifeMapLayer::applyPostLayer(const GeoImage& canvas, const TileKey& key, Layer* postLayer, ProgressCallback* progress) const
{
auto coverageLayer = dynamic_cast<CoverageLayer*>(postLayer);
if (coverageLayer && canvas.valid())
{
// Is there any way to actually type-check this?
auto factory = LandCoverSample::Factory::create(coverageLayer);

auto coverage = factory->createCoverage(key, progress);

if (coverage.valid() && !coverage.empty())
{
// landcover material index lookup table:
// TODO: read this ONCE and store as a member - createImageImpl uses it too.
std::unordered_map<std::string, unsigned> materialLUT;
if (getBiomeLayer())
{
unsigned ptr = 0;
for (auto& material : getBiomeLayer()->getBiomeCatalog()->getAssets().getMaterials())
{
materialLUT[material.name().get()] = ptr++;
}
}

auto result_image = osg::clone(canvas.getImage(), osg::CopyOp::DEEP_COPY_ALL);

ImageUtils::PixelReader read_canvas(canvas.getImage());
ImageUtils::PixelWriter write_result(result_image);

const auto& extent = canvas.getExtent();

for (unsigned t = 0; t < read_canvas.t(); ++t)
{
double v = (double)t / (double)read_canvas.t();
for (unsigned s = 0; s < read_canvas.s(); ++s)
{
double u = (double)s / (double)read_canvas.s();

// do we need to offset this be half a 'pixel'?
double x = extent.xMin() + u * extent.width();
double y = extent.yMin() + v * extent.height();

auto* sample = coverage.readAtCoords(x, y);
if (sample)
{
// populate the pixel with the original values:
osg::Vec4 value;
read_canvas(value, s, t);

// overwrite with the coverage data:
if (sample->rugged().isSet())
value[LIFEMAP_RUGGED] = sample->rugged().value();
if (sample->dense().isSet())
value[LIFEMAP_DENSE] = sample->dense().value();
if (sample->lush().isSet())
value[LIFEMAP_LUSH] = sample->lush().value();

if (sample->material().isSet())
{
// land cover asked for a custom material. Find its index.
auto i = materialLUT.find(sample->material().value());
if (i != materialLUT.end())
value[LIFEMAP_SPECIAL] = (i->second + 1);
}

write_result(value, s, t);
}
}
}

return GeoImage(result_image, canvas.getExtent());
}
}

return super::applyPostLayer(canvas, key, postLayer, progress);
}

0 comments on commit d3c0ced

Please sign in to comment.