/* osgEarth
 * Copyright 2025 Pelican Mapping
 * MIT License
 */
#ifndef OSGEARTH_LAYER_SHADER_H
#define OSGEARTH_LAYER_SHADER_H 1

#include <osgEarth/Config>
#include <osgEarth/URI>
#include <osgEarth/TerrainResources>
#include <osgEarth/PBRMaterial>
#include <osgDB/Options>
#include <vector>
#include <string>

namespace osg {
    class StateSet;
}
namespace osgEarth {
    class Layer;
}

namespace osgEarth { namespace Util
{
    using namespace osgEarth;

    //! Serializable shader that supports samplers and uniforms
    //! in an earth file.
    class OSGEARTH_EXPORT ShaderOptions : public ConfigOptions
    {
    public:
        META_ConfigOptions(osgEarth, ShaderOptions, ConfigOptions);

        struct Sampler
        {
            std::string      _name;
            std::vector<URI> _uris;
        };

        struct Uniform
        {
            std::string _name;
            optional<float> _floatValue;
            optional<osg::Vec3f> _vec3Value;
        };

        struct PBRSampler
        {
            std::string _name;
            PBRMaterial _material;
        };

        void apply(osg::StateSet*, Layer*, TerrainResources*, const osgDB::Options*);

    public:
        std::string& code() { return _code; }
        const std::string& code() const { return _code; }

        std::vector<Sampler>& samplers() { return _samplers; }
        const std::vector<Sampler>& samplers() const { return _samplers; }

        std::vector<Uniform>& uniforms() { return _uniforms; }
        const std::vector<Uniform>& uniforms() const { return _uniforms; }

        optional<PBRSampler>& pbrsampler() { return _pbrsampler; }
        const optional<PBRSampler>& pbrsampler() const { return _pbrsampler; }

    public:
        virtual Config getConfig() const;

    private:
        void fromConfig(const Config& conf);

    private:
        std::string _code;
        std::vector<Sampler> _samplers;
        std::vector<Uniform>  _uniforms;
        optional<PBRSampler> _pbrsampler;
    };

    //! Encapsulates a shader attached to a Layer (or other object).
    /* internal */ class LayerShader : public osg::Referenced
    {
    public:
        LayerShader(const ShaderOptions& options);

        void install(Layer* layer, TerrainResources* res);

    protected:
        virtual ~LayerShader();

    private:
        const ShaderOptions _options;
        std::vector<TextureImageUnitReservation> _reservations;
    };

} } // namespace osgEarth

OSGEARTH_SPECIALIZE_CONFIG(osgEarth::Util::ShaderOptions);

#endif // OSGEARTH_LAYER_SHADER_H

