/* osgEarth
 * Copyright 2025 Pelican Mapping
 * MIT License
 */

#ifndef OSGEARTH_SDF_H
#define OSGEARTH_SDF_H

#include <osgEarth/Common>
#include <osgEarth/Feature>
#include <osgEarth/GLUtils>
#include <osg/Image>

namespace osg {
    class Uniform;
}

namespace osgEarth { namespace Util
{
    class Session;

    class OSGEARTH_EXPORT SDFGenerator
    {
    public:
        SDFGenerator();

        //! Allocate a new SDF image
        //! @param size X and Y dimension; must be a power of 2
        //! @param extent Geospatial extent
        GeoImage allocateSDF(
            unsigned size,
            const GeoExtent& extent,
            GLenum pixelFormat =GL_RED) const;

        //! Encode a nearest-neighbor field for vector data. Each pixel contains
        //! the coordinates of the nearest pixel with feature data. The coordinate
        //! system is [x,y] relate to the lower-left corner.
        //!
        //! You can pass this field to the createDistanceField function to convert
        //! it to a distance field.
        //!
        //! @param features Features to use for distance calculation
        //! @param nnfieldSize Size of raster to create
        //! @param extent Geospatial extent of the raster
        //! @param nnfield Input/output nearest neighbor field
        //! @param inverted Whether to test empty pixels instead of full pixels
        //! @param progress Progress tracker object
        //! @return True upon success
        bool createNearestNeighborField(
            const FeatureList& features,
            unsigned nnfieldSize,
            const GeoExtent& extent,
            bool inverted,
            GeoImage& nnfield,
            Cancelable* progress) const;

        //! Encode a nearest-neighbor field from a raster image.
        //! The input raster is typically rasterized feature data, but can be
        //! anything.
        //!
        //! You can pass this field to the createDistanceField function to convert
        //! it to a distance field.
        //!
        //! @param input Input raster data
        //! @param inverted Whether to test empty pixels instead of full pixels
        //! @param nnfield Input/output nearest neighbor field
        //! @param progress Progress tracker object
        //! @return True upon success
        bool createNearestNeighborField(
            const GeoImage& input,
            bool inverted,
            GeoImage& nnfield,
            Cancelable* progress) const;

        //! Encode a distance field into an image.
        //! @param nnfield Input NN Field to conver to a distance field
        //! @param sdf Distance field to populate (additively). Distance values are
        //!    in the range [0..1] normalized from the min_dist and max_dist inputs.
        //! @param min_dist Distances <= min_dist are encoded as 0.0
        //! @param max_dist Distances >= max_dist are encoded as 1.0
        //! @param progress Progress tracker object
        void createDistanceField(
            const GeoImage& nnfield,
            GeoImage& sdf,
            float tile_size,
            float min_dist,
            float max_dist,
            Cancelable* progress) const;

        //! Whether to permit use of the GPU. Set this to true if there
        //! is a running frame loop with an active graphics context available
        //! and you are willing to shunt the processing to the GPU.
        void setUseGPU(bool value);

        //! Computes the distance field from an image using the technique described in http://cs.brown.edu/people/pfelzens/papers/dt-final.pdf
        //! A great visualization of this algorithm is at https://observablehq.com/@mourner/fast-distance-transform
        //! @param image The image to compute the distance field from with an alpha value of 0 indicating empty pixels
        //! @param minPixels Pixel distances <= minPixels are encoded as 0.0
        //! @param maxPixels Pixel distances >= maxPixels are encoded as 1.0
        osg::Image* createDistanceField(const osg::Image* image, float minPixels, float maxPixels) const;

    private:

        void compute_nnf_on_cpu(osg::Image* buf) const;
        bool _useGPU;

    };
} } // osgEarth::Util


#endif // OSGEARTH_SDF_H
