text: /**
   * PANDA 3D SOFTWARE
   * Copyright (c) Carnegie Mellon University.  All rights reserved.
   *
   * All use of this software is subject to the terms of the revised BSD
   * license.  You should have received a copy of this license along
   * with this source code in a file named "LICENSE."
   *
   * @file shader.h
   * @author jyelon
   * @date 2005-09-01
   * @author fperazzi, PandaSE
   * @date 2010-04-29
   */
  
  #ifndef SHADER_H
  #define SHADER_H
  
  #include "pandabase.h"
  #include "config_gobj.h"
  #include "typedWritableReferenceCount.h"
  #include "namable.h"
  #include "graphicsStateGuardianBase.h"
  #include "internalName.h"
  #include "pta_int.h"
  #include "pta_float.h"
  #include "pta_double.h"
  #include "pta_stdfloat.h"
  #include "pta_LMatrix4.h"
  #include "pta_LMatrix3.h"
  #include "pta_LVecBase4.h"
  #include "pta_LVecBase3.h"
  #include "pta_LVecBase2.h"
  #include "epvector.h"
  #include "asyncFuture.h"
  #include "bamCacheRecord.h"
  
  #ifdef HAVE_CG
  // I don't want to include the Cg header file into panda as a whole.  Instead,
  // I'll just excerpt some opaque declarations.
  typedef struct _CGcontext   *CGcontext;
  typedef struct _CGprogram   *CGprogram;
  typedef struct _CGparameter *CGparameter;
  #endif
  
  /**
  
   */
  class EXPCL_PANDA_GOBJ Shader : public TypedWritableReferenceCount {
  PUBLISHED:
    enum ShaderLanguage {
      SL_none,
      SL_Cg,
      SL_GLSL,
      SL_HLSL,
      SL_SPIR_V,
    };
  
    enum ShaderType {
      ST_none = 0,
      ST_vertex,
      ST_fragment,
      ST_geometry,
      ST_tess_control,
      ST_tess_evaluation,
      ST_compute,
      ST_COUNT
    };
  
    enum AutoShaderSwitch {
      AS_normal = 0x01,
      AS_glow   = 0x02,
      AS_gloss  = 0x04,
      AS_ramp   = 0x08,
      AS_shadow = 0x10,
    };
  
    enum AutoShaderBit {
      bit_AutoShaderNormal = 0, // bit for AS_normal
      bit_AutoShaderGlow   = 1, // bit for AS_glow
      bit_AutoShaderGloss  = 2, // bit for AS_gloss
      bit_AutoShaderRamp   = 3, // bit for AS_ramp
      bit_AutoShaderShadow = 4, // bit for AS_shadow
    };
  
    static PT(Shader) load(const Filename &file, ShaderLanguage lang = SL_none);
    static PT(Shader) make(std::string body, ShaderLanguage lang = SL_none);
    static PT(Shader) load(ShaderLanguage lang,
                           const Filename &vertex, const Filename &fragment,
                           const Filename &geometry = "",
                           const Filename &tess_control = "",
                           const Filename &tess_evaluation = "");
    static PT(Shader) load_compute(ShaderLanguage lang, const Filename &fn);
    static PT(Shader) make(ShaderLanguage lang,
                           std::string vertex, std::string fragment,
                           std::string geometry = "",
                           std::string tess_control = "",
                           std::string tess_evaluation = "");
    static PT(Shader) make_compute(ShaderLanguage lang, std::string body);
  
    INLINE Filename get_filename(ShaderType type = ST_none) const;
    INLINE void set_filename(ShaderType type, const Filename &filename);
    INLINE const std::string &get_text(ShaderType type = ST_none) const;
    INLINE bool get_error_flag() const;
    INLINE ShaderLanguage get_language() const;
  
    INLINE bool has_fullpath() const;
    INLINE const Filename &get_fullpath() const;
  
    INLINE bool get_cache_compiled_shader() const;
    INLINE void set_cache_compiled_shader(bool flag);
  
    PT(AsyncFuture) prepare(PreparedGraphicsObjects *prepared_objects);
    bool is_prepared(PreparedGraphicsObjects *prepared_objects) const;
    bool release(PreparedGraphicsObjects *prepared_objects);
    int release_all();
  
    ShaderContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
                               GraphicsStateGuardianBase *gsg);
  
  public:
    enum ShaderMatInput {
      SMO_identity,
  
      SMO_window_size,
      SMO_pixel_size,
      SMO_texpad_x,
      SMO_texpix_x,
  
      SMO_attr_material,
      SMO_attr_color,
      SMO_attr_colorscale,
  
      SMO_alight_x,
      SMO_dlight_x,
      SMO_plight_x,
      SMO_slight_x,
      SMO_satten_x,
      SMO_texmat_i,
      SMO_plane_x,
      SMO_clipplane_x,
  
      SMO_mat_constant_x,
      SMO_vec_constant_x,
  
      SMO_world_to_view,
      SMO_view_to_world,
  
      SMO_model_to_view,
      SMO_view_to_model,
  
      SMO_apiview_to_view,
      SMO_view_to_apiview,
  
      SMO_clip_to_view,
      SMO_view_to_clip,
  
      SMO_apiclip_to_view,
      SMO_view_to_apiclip,
  
      SMO_view_x_to_view,
      SMO_view_to_view_x,
  
      SMO_apiview_x_to_view,
      SMO_view_to_apiview_x,
  
      SMO_clip_x_to_view,
      SMO_view_to_clip_x,
  
      SMO_apiclip_x_to_view,
      SMO_view_to_apiclip_x,
  
      SMO_attr_fog,
      SMO_attr_fogcolor,
  
      SMO_frame_number,
      SMO_frame_time,
      SMO_frame_delta,
  
      SMO_mat_constant_x_attrib,
      SMO_vec_constant_x_attrib,
  
      SMO_light_ambient,
      SMO_light_source_i_attrib,
  
      SMO_light_product_i_ambient,
      SMO_light_product_i_diffuse,
      SMO_light_product_i_specular,
  
      // SMO_clipplane_x is world coords, GLSL needs eye coords
      SMO_apiview_clipplane_i,
  
      SMO_model_to_apiview,
      SMO_apiview_to_model,
      SMO_apiview_to_apiclip,
      SMO_apiclip_to_apiview,
  
      SMO_inv_texmat_i,
  
      // Additional properties for PBR materials
      SMO_attr_material2,
  
      // Hack for text rendering.  Don't use in user shaders.
      SMO_tex_is_alpha_i,
  
      SMO_transform_i,
      SMO_slider_i,
  
      SMO_light_source_i_packed,
  
      // Texture scale component of texture matrix.
      SMO_texscale_i,
  
      // Color of an M_blend texture stage.
      SMO_texcolor_i,
  
      SMO_INVALID
    };
  
    enum ShaderTexInput {
      STO_INVALID,
  
      STO_named_input,
      STO_named_stage,
  
      STO_stage_i,
      STO_light_i_shadow_map,
    };
  
    enum ShaderArgClass {
      SAC_scalar,
      SAC_vector,
      SAC_matrix,
      SAC_sampler,
      SAC_array,
      SAC_unknown,
    };
  
    enum ShaderArgType {
      SAT_scalar,
      SAT_vec1,
      SAT_vec2,
      SAT_vec3,
      SAT_vec4,
      SAT_mat1x1,
      SAT_mat1x2,
      SAT_mat1x3,
      SAT_mat1x4,
      SAT_mat2x1,
      SAT_mat2x2,
      SAT_mat2x3,
      SAT_mat2x4,
      SAT_mat3x1,
      SAT_mat3x2,
      SAT_mat3x3,
      SAT_mat3x4,
      SAT_mat4x1,
      SAT_mat4x2,
      SAT_mat4x3,
      SAT_mat4x4,
      SAT_sampler1d,
      SAT_sampler2d,
      SAT_sampler3d,
      SAT_sampler2d_array,
      SAT_sampler_cube,
      SAT_sampler_buffer,
      SAT_sampler_cube_array,
      SAT_unknown
  };
  
    enum ShaderArgDir {
      SAD_in,
      SAD_out,
      SAD_inout,
      SAD_unknown,
    };
  
    enum ShaderMatPiece {
      SMP_whole,
      SMP_transpose,
      SMP_row0,
      SMP_row1,
      SMP_row2,
      SMP_row3,
      SMP_col0,
      SMP_col1,
      SMP_col2,
      SMP_col3,
      SMP_row3x1,
      SMP_row3x2,
      SMP_row3x3,
      SMP_upper3x3,
      SMP_transpose3x3,
      SMP_cell15,
      SMP_cell14,
      SMP_cell13,
    };
  
    enum ShaderStateDep {
      SSD_NONE          = 0x000,
      SSD_general       = 0x001,
      SSD_transform    = 0x2002,
      SSD_color         = 0x004,
      SSD_colorscale    = 0x008,
      SSD_material      = 0x010,
      SSD_shaderinputs  = 0x020,
      SSD_fog           = 0x040,
      SSD_light         = 0x080,
      SSD_clip_planes   = 0x100,
      SSD_tex_matrix    = 0x200,
      SSD_frame         = 0x400,
      SSD_projection    = 0x800,
      SSD_texture      = 0x1000,
      SSD_view_transform= 0x2000,
    };
  
    enum ShaderBug {
      SBUG_ati_draw_buffers,
    };
  
    enum ShaderMatFunc {
      SMF_compose,
      SMF_transform_dlight,
      SMF_transform_plight,
      SMF_transform_slight,
      SMF_first,
    };
  
    struct ShaderArgId {
      std::string     _name;
      ShaderType _type;
      int        _seqno;
    };
  
    enum ShaderPtrType {
      SPT_float,
      SPT_double,
      SPT_int,
      SPT_uint,
      SPT_unknown
    };
  
    struct ShaderArgInfo {
      ShaderArgId       _id;
      ShaderArgClass    _class;
      ShaderArgClass    _subclass;
      ShaderArgType     _type;
      ShaderArgDir      _direction;
      bool              _varying;
      ShaderPtrType     _numeric_type;
      NotifyCategory   *_cat;
    };
  
    // Container structure for data of parameters ShaderPtrSpec.
    struct ShaderPtrData {
    private:
      PT(ReferenceCount) _pta;
  
    public:
      void *_ptr;
      ShaderPtrType _type;
      bool _updated;
      size_t _size; //number of elements vec3[4]=12
  
    public:
      INLINE ShaderPtrData();
      INLINE ShaderPtrData(const PTA_float &ptr);
      INLINE ShaderPtrData(const PTA_LVecBase4f &ptr);
      INLINE ShaderPtrData(const PTA_LVecBase3f &ptr);
      INLINE ShaderPtrData(const PTA_LVecBase2f &ptr);
      INLINE ShaderPtrData(const PTA_LMatrix4f &mat);
      INLINE ShaderPtrData(const PTA_LMatrix3f &mat);
      INLINE ShaderPtrData(const LVecBase4f &vec);
      INLINE ShaderPtrData(const LVecBase3f &vec);
      INLINE ShaderPtrData(const LVecBase2f &vec);
      INLINE ShaderPtrData(const LMatrix4f &mat);
      INLINE ShaderPtrData(const LMatrix3f &mat);
  
      INLINE ShaderPtrData(const PTA_double &ptr);
      INLINE ShaderPtrData(const PTA_LVecBase4d &ptr);
      INLINE ShaderPtrData(const PTA_LVecBase3d &ptr);
      INLINE ShaderPtrData(const PTA_LVecBase2d &ptr);
      INLINE ShaderPtrData(const PTA_LMatrix4d &mat);
      INLINE ShaderPtrData(const PTA_LMatrix3d &mat);
      INLINE ShaderPtrData(const LVecBase4d &vec);
      INLINE ShaderPtrData(const LVecBase3d &vec);
      INLINE ShaderPtrData(const LVecBase2d &vec);
      INLINE ShaderPtrData(const LMatrix4d &mat);
      INLINE ShaderPtrData(const LMatrix3d &mat);
  
      INLINE ShaderPtrData(const PTA_int &ptr);
      INLINE ShaderPtrData(const PTA_LVecBase4i &ptr);
      INLINE ShaderPtrData(const PTA_LVecBase3i &ptr);
      INLINE ShaderPtrData(const PTA_LVecBase2i &ptr);
      INLINE ShaderPtrData(const LVecBase4i &vec);
      INLINE ShaderPtrData(const LVecBase3i &vec);
      INLINE ShaderPtrData(const LVecBase2i &vec);
  
      INLINE void write_datagram(Datagram &dg) const;
      INLINE void read_datagram(DatagramIterator &source);
    };
  
    struct ShaderMatSpec {
      LMatrix4          _cache[2];
      LMatrix4          _value;
      ShaderArgId       _id;
      ShaderMatFunc     _func;
      ShaderMatInput    _part[2];
      PT(InternalName)  _arg[2];
      int               _dep[2];
      int               _index;
      ShaderMatPiece    _piece;
    };
  
    struct ShaderTexSpec {
      ShaderArgId       _id;
      PT(InternalName)  _name;
      ShaderTexInput    _part;
      int               _stage;
      int               _desired_type;
      PT(InternalName)  _suffix;
    };
  
    struct ShaderVarSpec {
      ShaderArgId       _id;
      PT(InternalName)  _name;
      int               _append_uv;
      int               _elements;
      ShaderPtrType     _numeric_type;
    };
  
    struct ShaderPtrSpec {
      ShaderArgId       _id;
      int               _dim[3]; //n_elements,rows,cols
      int               _dep[2];
      PT(InternalName)  _arg;
      ShaderArgInfo     _info;
      ShaderPtrType     _type;
    };
  
    class EXPCL_PANDA_GOBJ ShaderCaps {
    public:
      void clear();
      INLINE bool operator == (const ShaderCaps &other) const;
      INLINE ShaderCaps();
  
    public:
      bool _supports_glsl;
  
  #ifdef HAVE_CG
      int _active_vprofile;
      int _active_fprofile;
      int _active_gprofile;
      int _active_tprofile;
  
      int _ultimate_vprofile;
      int _ultimate_fprofile;
      int _ultimate_gprofile;
      int _ultimate_tprofile;
  
      pset <ShaderBug> _bug_list;
  #endif
    };
  
    class ShaderFile : public ReferenceCount {
    public:
      INLINE ShaderFile() {};
      INLINE ShaderFile(std::string shared);
      INLINE ShaderFile(std::string vertex, std::string fragment, std::string geometry,
                        std::string tess_control, std::string tess_evaluation);
  
      INLINE void write_datagram(Datagram &dg) const;
      INLINE void read_datagram(DatagramIterator &source);
  
      INLINE bool operator < (const ShaderFile &other) const;
  
    public:
      bool _separate;
      std::string _shared;
      std::string _vertex;
      std::string _fragment;
      std::string _geometry;
      std::string _tess_control;
      std::string _tess_evaluation;
      std::string _compute;
    };
  
  public:
    // These routines help split the shader into sections, for those shader
    // implementations that need to do so.  Don't use them when you use separate
    // shader programs.
    void parse_init();
    void parse_line(std::string &result, bool rt, bool lt);
    void parse_upto(std::string &result, std::string pattern, bool include);
    void parse_rest(std::string &result);
    bool parse_eof();
  
    void cp_report_error(ShaderArgInfo &arg, const std::string &msg);
    bool cp_errchk_parameter_words(ShaderArgInfo &arg, int len);
    bool cp_errchk_parameter_in(ShaderArgInfo &arg);
    bool cp_errchk_parameter_ptr(ShaderArgInfo &p);
    bool cp_errchk_parameter_varying(ShaderArgInfo &arg);
    bool cp_errchk_parameter_uniform(ShaderArgInfo &arg);
    bool cp_errchk_parameter_float(ShaderArgInfo &arg, int lo, int hi);
    bool cp_errchk_parameter_sampler(ShaderArgInfo &arg);
    bool cp_parse_eol(ShaderArgInfo &arg,
                      vector_string &pieces, int &next);
    bool cp_parse_delimiter(ShaderArgInfo &arg,
                            vector_string &pieces, int &next);
    std::string cp_parse_non_delimiter(vector_string &pieces, int &next);
    bool cp_parse_coord_sys(ShaderArgInfo &arg,
                            vector_string &pieces, int &next,
                            ShaderMatSpec &spec, bool fromflag);
    int cp_dependency(ShaderMatInput inp);
    void cp_optimize_mat_spec(ShaderMatSpec &spec);
  
  #ifdef HAVE_CG
    void cg_recurse_parameters(CGparameter parameter,
                            const ShaderType &type,
                            bool &success);
  #endif
  
    bool compile_parameter(ShaderArgInfo &p, int *arg_dim);
  
    void clear_parameters();
  
    void set_compiled(unsigned int format, const char *data, size_t length);
    bool get_compiled(unsigned int &format, std::string &binary) const;
  
  private:
  #ifdef HAVE_CG
    ShaderArgClass cg_parameter_class(CGparameter p);
    ShaderArgType cg_parameter_type(CGparameter p);
    ShaderArgDir cg_parameter_dir(CGparameter p);
  
    CGprogram cg_compile_entry_point(const char *entry, const ShaderCaps &caps,
                                     CGcontext context, ShaderType type);
  
    bool cg_analyze_entry_point(CGprogram prog, ShaderType type);
  
    bool cg_analyze_shader(const ShaderCaps &caps);
    bool cg_compile_shader(const ShaderCaps &caps, CGcontext context);
    void cg_release_resources();
    void cg_report_errors();
  
    // Determines the appropriate cg profile settings and stores them in the
    // active shader caps based on any profile settings stored in the shader's
    // header
    void cg_get_profile_from_header(ShaderCaps &caps);
  
    ShaderCaps _cg_last_caps;
    static CGcontext  _cg_context;
    CGprogram  _cg_vprogram;
    CGprogram  _cg_fprogram;
    CGprogram  _cg_gprogram;
  
    int _cg_vprofile;
    int _cg_fprofile;
    int _cg_gprofile;
  
    CGprogram cg_program_from_shadertype(ShaderType type);
  
  public:
    bool cg_compile_for(const ShaderCaps &caps, CGcontext context,
                        CGprogram &combined_program, pvector<CGparameter> &map);
  
  #endif
  
  public:
    pvector<ShaderPtrSpec> _ptr_spec;
    epvector<ShaderMatSpec> _mat_spec;
    pvector<ShaderTexSpec> _tex_spec;
    pvector<ShaderVarSpec> _var_spec;
    int _mat_deps;
  
    bool _error_flag;
    ShaderFile _text;
  
  protected:
    ShaderFile _filename;
    Filename _fullpath;
    int _parse;
    bool _loaded;
    ShaderLanguage _language;
  
    typedef pvector<Filename> Filenames;
    Filenames _included_files;
  
    // Stores full paths, and includes the fullpaths of the shaders themselves
    // as well as the includes.
    Filenames _source_files;
    time_t _last_modified;
  
    PT(BamCacheRecord) _record;
    bool _cache_compiled_shader;
    unsigned int _compiled_format;
    std::string _compiled_binary;
  
    static ShaderCaps _default_caps;
    static int _shaders_generated;
  
    typedef pmap<ShaderFile, PT(Shader)> ShaderTable;
  
    static ShaderTable _load_table;
    static ShaderTable _make_table;
  
    friend class ShaderContext;
    friend class PreparedGraphicsObjects;
  
    typedef pmap <PreparedGraphicsObjects *, ShaderContext *> Contexts;
    Contexts _contexts;
  
  private:
    void clear_prepared(PreparedGraphicsObjects *prepared_objects);
  
    Shader(ShaderLanguage lang);
  
    bool read(const ShaderFile &sfile, BamCacheRecord *record = nullptr);
    bool load(const ShaderFile &sbody, BamCacheRecord *record = nullptr);
    bool do_read_source(std::string &into, const Filename &fn, BamCacheRecord *record);
    bool do_load_source(std::string &into, const std::string &source, BamCacheRecord *record);
    bool r_preprocess_include(std::ostream &out, const Filename &fn,
                              const Filename &source_dir,
                              std::set<Filename> &open_files,
                              BamCacheRecord *record, int depth);
    bool r_preprocess_source(std::ostream &out, std::istream &in,
                             const Filename &fn, const Filename &full_fn,
                             std::set<Filename> &open_files,
                             BamCacheRecord *record,
                             int fileno = 0, int depth = 0);
  
    bool check_modified() const;
  
  public:
    ~Shader();
  
    Filename get_filename_from_index(int index, ShaderType type) const;
  
  public:
    static void register_with_read_factory();
    virtual void write_datagram(BamWriter *manager, Datagram &dg);
  
  protected:
    static TypedWritable *make_from_bam(const FactoryParams &params);
    void fillin(DatagramIterator &scan, BamReader *manager);
  
  public:
    static TypeHandle get_class_type() {
      return _type_handle;
    }
    static void init_type() {
      TypedWritableReferenceCount::init_type();
      register_type(_type_handle, "Shader",
                    TypedWritableReferenceCount::get_class_type());
    }
    virtual TypeHandle get_type() const {
      return get_class_type();
    }
    virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
  
  private:
    static TypeHandle _type_handle;
  };
  
  #include "shader.I"
  
  #endif
  