// ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // gl_shader.h // Neal Binnendyk, nealabq -at- gmail, nealabq.com // Copyright (c) 2010. All rights reserved. // # pragma once # ifndef GL_SHADER_H # define GL_SHADER_H // _______________________________________________________________________________________________ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # include "debug.h" # include "gl_env_global.h" # include // _______________________________________________________________________________________________ namespace gl_env { namespace shader { // _______________________________________________________________________________________________ class shader_program_owner_type ; class shader_program_type ; class shader_owner_type ; class shader_type ; // We will declare: // typedef ..variant-of-classes-above.. shader_program_variant_type; // To bad we cannot forward declare it somehow, maybe like this: // typename shader_program_variant_type; // _______________________________________________________________________________________________ // _______________________________________________________________________________________________ // // shader_object_base_type< id_type > // _______________________________________________________________________________________________ template< typename ID_TYPE > class shader_object_base_type { // Typedef public: typedef ID_TYPE id_type; // Assumes id_type has a fast copy. Otherwise we'd want to use "id_type const &" for // params and return values instead of just "id_type". // Ctor/dtor protected: /* ctor */ shader_object_base_type( ) : id_( 0 ) { } /* ctor */ shader_object_base_type( id_type id) : id_( id) { } // Default dtor // Default copy ctor // Default copy assignment // Reset public: bool is_reset( ) const { return 0 == get_id( ); } bool not_reset( ) const { return 0 != get_id( ); } void reset( ) { set_id( 0); } // Getter and Setter public: id_type get_id( ) const { return id_; } protected: void set_id( id_type id) { id_ = id; } // Member var, set in supertype private: id_type id_ ; }; // _______________________________________________________________________________________________ // _______________________________________________________________________________________________ // // shader_type // shader_owner_type // _______________________________________________________________________________________________ # define THIS_TYPE shader_type class THIS_TYPE : public shader_object_base_type< uint_type > { // Typedefs private: typedef shader_object_base_type< uint_type > base_type ; typedef THIS_TYPE this_type ; public: typedef base_type::id_type id_type ; /* uint_type */ typedef shader_owner_type owner_type ; // Ctor/Copy/Dtor public: /* ctor */ THIS_TYPE( ) { d_assert( is_reset( )); } // Default dtor // Default copy ctor // Default copy assignment /* ctor */ THIS_TYPE( owner_type const &) ; /* defined below in macros */ this_type & operator =( owner_type const &) ; /* defined below in macros */ // These will assert if id is not not a legal shader. /* ctor */ THIS_TYPE( id_type id) { set_id( id); } this_type & operator =( id_type id) { return set_id( id); } // Error checking wrapper on setter public: this_type & set_id( id_type id) { d_assert( (0 == id) || global::is_shader( id)); base_type::set_id( id); return *this; } }; # undef THIS_TYPE // _______________________________________________________________________________________________ # define THIS_TYPE shader_owner_type class THIS_TYPE { // Typedefs private: typedef THIS_TYPE this_type ; public: typedef shader_type holder_type ; typedef holder_type::id_type id_type ; /* uint_type */ BOOST_MPL_ASSERT(( boost::is_same< this_type, holder_type::owner_type >)); // Ctor/Dtor public: /* ctor */ THIS_TYPE( ) { d_assert( is_reset( )); } /* dtor */ ~THIS_TYPE( ) { reset( ); } // Disable copy -- we don't support multiple owners // No, unfortunately we have to choose between providing copy or not using variants. // So provide special highly-restricted copy that should only be used by the variant // implementation. public: /* copy */ THIS_TYPE( this_type const & b) { d_assert( b.is_reset( )); d_assert( is_reset( )); } void operator =( this_type const & b) { d_assert( b.is_reset( )); reset( ); } // Reset ctor // This was an attempt to get out of having to implement copy, above. // Unfortunately, it's not enough to satisfy boost variant. But it's still useful. public: struct reset_type { }; /* ctor */ THIS_TYPE( reset_type) { d_assert( is_reset( )); } void operator =( reset_type) { reset( ); } // Reset public: bool is_reset( ) const { return holder_.is_reset( ); } bool not_reset( ) const { return holder_.not_reset( ); } void reset( ) { if ( holder_.not_reset( ) ) { global::delete_shader( get_id( )); holder_.reset( ); } d_assert( is_reset( )); } // Getter public: id_type get_id( ) const { return holder_.get_id( ); } // Setter public: void create_shader( enum_type shader_tag, char_type const * p_src_string) { reset( ); holder_.set_id( global::create_shader( shader_tag, p_src_string)); } void create_vertex_shader( char_type const * p_src_string) { create_shader( GL_VERTEX_SHADER, p_src_string); } void create_fragment_shader( char_type const * p_src_string) { create_shader( GL_FRAGMENT_SHADER, p_src_string); } // Private member var private: holder_type holder_ ; }; # undef THIS_TYPE // _______________________________________________________________________________________________ // _______________________________________________________________________________________________ // // shader_program_type // shader_program_owner_type // _______________________________________________________________________________________________ # define THIS_TYPE shader_program_type class THIS_TYPE : public shader_object_base_type< uint_type > { // Typedefs private: typedef shader_object_base_type< uint_type > base_type ; typedef THIS_TYPE this_type ; public: typedef base_type::id_type id_type ; /* uint_type */ typedef shader_program_owner_type owner_type ; // Ctor/Copy/Dtor public: /* ctor */ THIS_TYPE( ) { d_assert( is_reset( )); } // Default dtor // Default copy ctor // Default copy assignment /* ctor */ THIS_TYPE( owner_type const &) ; /* defined below in macros */ this_type & operator =( owner_type const &) ; /* defined below in macros */ /* ctor */ THIS_TYPE( id_type id) { set_id( id); } this_type & operator =( id_type id) { set_id( id); return *this; } // Error checking wrapper on setter public: this_type & set_id( id_type id) { d_assert( (0 == id) || global::is_shader_program( id)); base_type::set_id( id); return *this; } // Make this the current shader program. public: this_type activate( ) const { this_type const previously_active_program = global::get_active_shader_program( ); global::use_shader_program( get_id( )); return previously_active_program; } }; # undef THIS_TYPE // _______________________________________________________________________________________________ # define THIS_TYPE shader_program_owner_type class THIS_TYPE { // Typedefs private: typedef THIS_TYPE this_type ; public: typedef shader_program_type holder_type ; typedef holder_type::id_type id_type ; /* uint_type */ BOOST_MPL_ASSERT(( boost::is_same< this_type, holder_type::owner_type >)); // Ctor/Dtor public: /* ctor */ THIS_TYPE( ) { d_assert( is_reset( )); } /* dtor */ ~THIS_TYPE( ) { reset( ); } // Disable copy -- we don't support multiple owners // No, unfortunately we have to choose between providing copy or not using variants. // So provide special highly-restricted copy that should only be used by the variant // implementation. public: /* copy */ THIS_TYPE( this_type const & b) { d_assert( b.is_reset( )); d_assert( is_reset( )); } void operator =( this_type const & b) { d_assert( b.is_reset( )); reset( ); } // Reset ctor // This was an attempt to get out of having to implement copy, above. // Unfortunately, it's not enough to satisfy boost variant. But it's still useful. public: struct reset_type { }; /* ctor */ THIS_TYPE( reset_type) { d_assert( is_reset( )); } void operator =( reset_type) { reset( ); } // Reset public: bool is_reset( ) const { return holder_.is_reset( ); } bool not_reset( ) const { return holder_.not_reset( ); } void reset( ) { if ( holder_.not_reset( ) ) { //global::detach_all_shaders( get_id( )); global::delete_shader_program( get_id( )); holder_.reset( ); } d_assert( is_reset( )); } // Getter public: id_type get_id( ) const { return holder_.get_id( ); } // Setter public: void create_shader_program ( shader_type const & vertex_shader , shader_type const & fragment_shader ) { reset( ); holder_.set_id( global::create_shader_program ( vertex_shader .get_id( ) , fragment_shader.get_id( ) )); } // Private member var private: holder_type holder_ ; }; # undef THIS_TYPE // _______________________________________________________________________________________________ // _______________________________________________________________________________________________ namespace ARB { // _______________________________________________________________________________________________ class shader_program_owner_type ; class shader_program_type ; class shader_owner_type ; class shader_type ; // _______________________________________________________________________________________________ // _______________________________________________________________________________________________ // // shader_type // shader_owner_type // _______________________________________________________________________________________________ # define THIS_TYPE shader_type class THIS_TYPE : public shader_object_base_type< GLhandleARB > { // Typedefs private: typedef shader_object_base_type< GLhandleARB > base_type ; typedef THIS_TYPE this_type ; public: typedef base_type::id_type id_type ; /* GLhandleARB */ typedef shader_owner_type owner_type ; // Ctor/Copy/Dtor public: /* ctor */ THIS_TYPE( ) { d_assert( is_reset( )); } // Default dtor // Default copy ctor // Default copy assignment /* ctor */ THIS_TYPE( owner_type const &) ; /* defined below in macros */ this_type & operator =( owner_type const &) ; /* defined below in macros */ // Problem: Because set_id(..) cannot check to make sure the id is OK, these are not safe. // Solution: Make these protected instead of public. Declare owner as friend. protected: /* ctor */ THIS_TYPE( id_type id) { set_id( id); } this_type & operator =( id_type id) { set_id( id); return *this; } // Error checking wrapper on setter // Solution: Make these protected instead of public. Declare owner as friend. protected: // Problem: These are not safe because there is no global::is_shader__ARB( id) predicate. this_type & set_id( id_type id) { //d_assert( (0 == id) || global::is_shader__ARB( id)); base_type::set_id( id); return *this; } friend class owner_type; }; # undef THIS_TYPE // _______________________________________________________________________________________________ # define THIS_TYPE shader_owner_type class THIS_TYPE { // Typedefs private: typedef THIS_TYPE this_type ; public: typedef shader_type holder_type ; typedef holder_type::id_type id_type ; /* GLhandleARB */ BOOST_MPL_ASSERT(( boost::is_same< this_type, holder_type::owner_type >)); // Ctor/Dtor public: /* ctor */ THIS_TYPE( ) { d_assert( is_reset( )); } /* dtor */ ~THIS_TYPE( ) { reset( ); } // Disable copy -- we don't support multiple owners // No, unfortunately we have to choose between providing copy or not using variants. // So provide special highly-restricted copy that should only be used by the variant // implementation. public: /* copy */ THIS_TYPE( this_type const & b) { d_assert( b.is_reset( )); d_assert( is_reset( )); } void operator =( this_type const & b) { d_assert( b.is_reset( )); reset( ); } // Reset ctor // This was an attempt to get out of having to implement copy, above. // Unfortunately, it's not enough to satisfy boost variant. But it's still useful. public: struct reset_type { }; /* ctor */ THIS_TYPE( reset_type) { d_assert( is_reset( )); } void operator =( reset_type) { reset( ); } // Reset public: bool is_reset( ) const { return holder_.is_reset( ); } bool not_reset( ) const { return holder_.not_reset( ); } void reset( ) { if ( holder_.not_reset( ) ) { //global::detach_all_shaders__ARB( get_id( )); global::delete_shader_object__ARB( get_id( )); holder_.reset( ); } d_assert( is_reset( )); } // Getter public: id_type get_id( ) const { return holder_.get_id( ); } // Setter public: void create_shader( enum_type shader_tag, char_type const * p_src_string) { reset( ); holder_.set_id( global::create_shader__ARB( shader_tag, p_src_string)); } void create_vertex_shader( char_type const * p_src_string) { create_shader( GL_VERTEX_SHADER_ARB, p_src_string); } void create_fragment_shader( char_type const * p_src_string) { create_shader( GL_FRAGMENT_SHADER_ARB, p_src_string); } // Private member var private: holder_type holder_ ; }; # undef THIS_TYPE // _______________________________________________________________________________________________ // _______________________________________________________________________________________________ // // shader_program_type // shader_program_owner_type // _______________________________________________________________________________________________ # define THIS_TYPE shader_program_type class THIS_TYPE : public shader_object_base_type< GLhandleARB > { // Typedefs private: typedef shader_object_base_type< GLhandleARB > base_type ; typedef THIS_TYPE this_type ; public: typedef base_type::id_type id_type ; /* GLhandleARB */ typedef shader_program_owner_type owner_type ; // Ctor/Copy/Dtor public: /* ctor */ THIS_TYPE( ) { d_assert( is_reset( )); } // Default dtor // Default copy ctor // Default copy assignment /* ctor */ THIS_TYPE( owner_type const &) ; /* defined below in macros */ this_type & operator =( owner_type const &) ; /* defined below in macros */ /* ctor */ THIS_TYPE( id_type id) { set_id( id); } this_type & operator =( id_type id) { set_id( id); return *this; } // Error checking wrapper on setter public: this_type & set_id( id_type id) { d_assert( (0 == id) || global::is_shader_program__ARB( id)); base_type::set_id( id); return *this; } // Make this the current shader program. public: this_type activate( ) const { this_type const previously_active_program = global::get_active_shader_program__ARB( ); global::use_shader_program__ARB( get_id( )); return previously_active_program; } }; # undef THIS_TYPE // _______________________________________________________________________________________________ # define THIS_TYPE shader_program_owner_type class THIS_TYPE { // Typedefs private: typedef THIS_TYPE this_type ; public: typedef shader_program_type holder_type ; typedef holder_type::id_type id_type ; /* GLhandleARB */ BOOST_MPL_ASSERT(( boost::is_same< this_type, holder_type::owner_type >)); // Ctor/Dtor public: /* ctor */ THIS_TYPE( ) { d_assert( is_reset( )); } /* dtor */ ~THIS_TYPE( ) { reset( ); } // Disable copy -- we don't support multiple owners // No, unfortunately we have to choose between providing copy or not using variants. // So provide special highly-restricted copy that should only be used by the variant // implementation. public: /* copy */ THIS_TYPE( this_type const & b) { d_assert( b.is_reset( )); d_assert( is_reset( )); } void operator =( this_type const & b) { d_assert( b.is_reset( )); reset( ); } // Reset ctor // This was an attempt to get out of having to implement copy, above. // Unfortunately, it's not enough to satisfy boost variant. But it's still useful. public: struct reset_type { }; /* ctor */ THIS_TYPE( reset_type) { d_assert( is_reset( )); } void operator =( reset_type) { reset( ); } // Reset public: bool is_reset( ) const { return holder_.is_reset( ); } bool not_reset( ) const { return holder_.not_reset( ); } void reset( ) { if ( holder_.not_reset( ) ) { global::delete_shader_object__ARB( get_id( )); holder_.reset( ); } d_assert( is_reset( )); } // Getter public: id_type get_id( ) const { return holder_.get_id( ); } // Setter public: void create_shader_program ( shader_type const & vertex_shader , shader_type const & fragment_shader ) { reset( ); holder_.set_id( global::create_shader_program__ARB ( vertex_shader .get_id( ) , fragment_shader.get_id( ) )); } // Private member var private: holder_type holder_ ; }; # undef THIS_TYPE // _______________________________________________________________________________________________ } /* end namespace ARB */ // _______________________________________________________________________________________________ // _______________________________________________________________________________________________ // // Define mixed-type methods and functions // // shader_type( shader_owner_type) - copy ctor // shader_type = shader_owner_type - copy assignment // // shader_type == shader_type - equality operator // shader_type < shader_type - inequality operator // // shader_owner_type == shader_owner_type - equality operator // shader_owner_type < shader_owner_type - inequality operator // // shader_type == shader_owner_type - equality operator // shader_type < shader_owner_type - inequality operator // // shader_owner_type == shader_type - equality operator // shader_owner_type < shader_type - inequality operator // _______________________________________________________________________________________________ # define DEFINE_COPY_CTOR_AND_ASSOP_( OWNER_TYPE, HOLDER_TYPE) \ inline HOLDER_TYPE::HOLDER_TYPE( OWNER_TYPE const & src) \ { set_id( src.get_id( )); } \ inline HOLDER_TYPE & HOLDER_TYPE::operator =( OWNER_TYPE const & src) \ { set_id( src.get_id( )); return *this; } /* end macro */ # define DEFINE_COMPARE_OP_( OP, A_TYPE, B_TYPE) \ inline bool operator OP( A_TYPE const & a, B_TYPE const & b) \ { return a.get_id( ) OP b.get_id( ); } /* end macro */ # define DEFINE_COMPARE_OPS_( OP, A_TYPE, B_TYPE) \ DEFINE_COMPARE_OP_( OP, A_TYPE, A_TYPE) \ DEFINE_COMPARE_OP_( OP, B_TYPE, B_TYPE) \ DEFINE_COMPARE_OP_( OP, A_TYPE, B_TYPE) \ DEFINE_COMPARE_OP_( OP, B_TYPE, A_TYPE) /* end macro */ # define DEFINE_CTOR_ASSOP_OPS( OWNER_TYPE, HOLDER_TYPE) \ DEFINE_COPY_CTOR_AND_ASSOP_( OWNER_TYPE, HOLDER_TYPE) \ DEFINE_COMPARE_OPS_( == , OWNER_TYPE, HOLDER_TYPE) \ DEFINE_COMPARE_OPS_( != , OWNER_TYPE, HOLDER_TYPE) \ DEFINE_COMPARE_OPS_( < , OWNER_TYPE, HOLDER_TYPE) /* end macro */ // _______________________________________________________________________________________________ DEFINE_CTOR_ASSOP_OPS( shader_owner_type , shader_type ) DEFINE_CTOR_ASSOP_OPS( shader_program_owner_type, shader_program_type ) namespace ARB { DEFINE_CTOR_ASSOP_OPS( shader_owner_type , shader_type ) DEFINE_CTOR_ASSOP_OPS( shader_program_owner_type, shader_program_type ) } /* end namespace ARB */ // _______________________________________________________________________________________________ # undef DEFINE_CTOR_ASSOP_OPS # undef DEFINE_COMPARE_OPS_ # undef DEFINE_COMPARE_OP_ # undef DEFINE_COPY_CTOR_AND_ASSOP_ // _______________________________________________________________________________________________ // _______________________________________________________________________________________________ struct reset_type { }; typedef boost::variant < reset_type , shader_program_type , ARB::shader_program_type > shader_program_variant_type ; typedef boost::variant < reset_type , shader_program_owner_type , ARB::shader_program_owner_type > shader_program_owner_variant_type ; typedef boost::variant < reset_type , shader_owner_type , ARB::shader_owner_type > shader_owner_variant_type ; // _______________________________________________________________________________________________ // _______________________________________________________________________________________________ /* owner class for holding a shader program and it's associated vertex & fragment shaders */ class shader_program_owner_any_type { // Ctor and dtor. public: /* ctor */ shader_program_owner_any_type ( char const * p_src_vertex_shader , char const * p_src_fragment_shader ) ; /* dtor */ ~shader_program_owner_any_type( ) { } // Copy is disabled because member vars do not support it. // Getters public: bool is_init_attempted( ) const { return is_init_attempted_; } bool is_init_successful( ) const { return is_init_successful_; } shader_program_variant_type get_shader_program( ) /* NOT const */ { init( ); return get_shader_program__no_init( ); } shader_program_variant_type get_shader_program__no_init( ) const ; // Init public: void init( ) { if ( ! is_init_attempted( ) ) { init_private( ); } d_assert( is_init_attempted( )); } void uninit( ) ; protected: void init_private( ) ; bool create_vertex_shader__normal( ) ; bool create_fragment_shader__normal( ) ; bool create_shader_program__normal( ) ; bool create_vertex_shader__ARB( ) ; bool create_fragment_shader__ARB( ) ; bool create_shader_program__ARB( ) ; // Private member vars private: bool is_init_attempted_ ; bool is_init_successful_ ; char const * const p_vertex_shader_src_ ; shader_owner_variant_type vertex_shader_ ; char const * const p_fragment_shader_src_ ; shader_owner_variant_type fragment_shader_ ; shader_program_owner_variant_type shader_program_ ; }; // _______________________________________________________________________________________________ // _______________________________________________________________________________________________ /* wrapper class for activating shader programs */ class with_shader_program // // Avoid using this to push an ARB shader on top of a normal shader, and vice versa. { // Wrapper ctor/dtors public: /* ctor */ with_shader_program( ) ; /* ctor */ with_shader_program( shader_program_owner_any_type &) ; /* ctor */ with_shader_program( shader_program_owner_any_type const &) ; /* ctor */ with_shader_program( shader_program_variant_type const &) ; /* dtor */ ~with_shader_program( ) { restore( ); } // Disable copy private: /* copy */ with_shader_program( with_shader_program const &) ; // no implementation void operator =( with_shader_program const &) ; // no implementation public: static bool is_reset( shader_program_variant_type const &) ; bool has_restore( ) const ; bool restore( ) ; bool forget__no_restore( ) ; bool activate( shader_program_owner_any_type &) ; bool activate__no_init( shader_program_owner_any_type const &) ; bool activate( shader_program_variant_type const &) ; protected: static shader_program_variant_type /* returns last activated */ activate_private( shader_program_variant_type const &) ; // Member vars private: shader_program_variant_type previous_program_shader_ ; }; // _______________________________________________________________________________________________ } /* end namespace shader */ } /* end namespace gl_env */ // _______________________________________________________________________________________________ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # endif // ifndef GL_SHADER_H // // gl_shader.h - End of File // _______________________________________________________________________________________________ // |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||