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

#ifndef OSGEARTH_HORIZON_CLIP_PLANE_H
#define OSGEARTH_HORIZON_CLIP_PLANE_H 1

#include <osgEarth/Common>
#include <osgEarth/Horizon>
#include <osgEarth/Containers>
#include <osg/NodeCallback>
#include <osg/CoordinateSystemNode>
#include <osg/Plane>

namespace osgEarth
{
    /**
     * Installs an OpenGL clip plane that will clip graphics
     * at the geocentric horizon. Usage:
     *
     *   HorizonClipPlane* hcp = new HorizonClipPlane();
     *   hcp->setClipPlaneNumber(0);
     *   mapNode->addCullCallback(hcp);
     *
     * Then, anywhere under that node that you want to apply clipping:
     *
     *   node->getOrCreateStateSet()->setMode(GL_CLIP_DISTANCE0, 1);
     */
    class OSGEARTH_EXPORT HorizonClipPlane : public osg::NodeCallback
    {
    public:
        //! Construct a new horizon clip plane with default (WGS84) ellipsoid
        HorizonClipPlane();

        //! Construct a new horizon clip plane with specific ellipsoid
        HorizonClipPlane(const Ellipsoid&);

        //! Set the GL clip plane to use. Default is zero.
        void setClipPlaneNumber(unsigned n);
        unsigned getClipPlaneNumber() const { return _num; }

    public: // osg::NodeCallback

        void operator()(osg::Node* node, osg::NodeVisitor* nv);

    public: // osg::Object

        virtual void resizeGLObjectBuffers(unsigned maxSize);
        virtual void releaseGLObjects(osg::State* state) const;

    private:

        unsigned _num;
        Ellipsoid _ellipsoid;

        struct PerCameraData {
            osg::ref_ptr<Horizon> horizon;
            osg::ref_ptr<osg::StateSet> stateSet;
            osg::ref_ptr<osg::Uniform> uniform;
        };
        typedef PerObjectFastMap<osg::Camera*, PerCameraData> DataMap;
        DataMap _data;

        struct ResizeFunctor : public DataMap::Functor {
            unsigned _s;
            ResizeFunctor(unsigned s) : _s(s) { }
            virtual void operator()(PerCameraData& data);
        };
        struct ReleaseFunctor : public DataMap::ConstFunctor {
            osg::State* _state;
            ReleaseFunctor(osg::State* state) : _state(state) { }
            virtual void operator()(const PerCameraData& data) const;
        };
    };

} // namespace osgEarth

#endif // OSGEARTH_HORIZON_CLIP_PLANE_H
