// Copyright (C) 2012-2015 ChaosForge Ltd // http://chaosforge.org/ // // This file is part of Nova libraries. // For conditions of distribution and use, see copying.txt file in root folder. /** * @file device.hh * @author Kornel Kisielewicz epyon@chaosforge.org * @brief Device class */ #ifndef NV_INTERFACE_DEVICE_HH #define NV_INTERFACE_DEVICE_HH #include #include #include #include #include #include #include namespace nv { class window; enum output_slot { OUTPUT_0 = 0, OUTPUT_1 = 1, OUTPUT_2 = 2, OUTPUT_3 = 3, OUTPUT_4 = 4, OUTPUT_5 = 5, OUTPUT_6 = 6, OUTPUT_7 = 7, OUTPUT_NONE = 16, OUTPUT_FRONT = 17, OUTPUT_BACK = 18, }; enum texture_type { TEXTURE_1D, TEXTURE_2D, TEXTURE_RECT, TEXTURE_3D, TEXTURE_CUBE, TEXTURE_1D_ARRAY, TEXTURE_2D_ARRAY, TEXTURE_1D_BUFFER, }; enum texture_slot { TEX_DIFFUSE = 0, TEX_NORMAL = 1, TEX_METALLIC = 2, TEX_SPECULAR = 2, // obsolete TEX_ROUGHNESS = 3, TEX_GLOSS = 3, // obsolete TEX_EMISSIVE = 4, TEXTURE_0 = 0, TEXTURE_1 = 1, TEXTURE_2 = 2, TEXTURE_3 = 3, TEXTURE_4 = 4, TEXTURE_5 = 5, TEXTURE_6 = 6, TEXTURE_7 = 7, TEXTURE_8 = 8, TEXTURE_9 = 9, TEXTURE_10 = 10, TEXTURE_11 = 11, TEXTURE_12 = 12, TEXTURE_13 = 13, TEXTURE_14 = 14, TEXTURE_15 = 15, }; struct attribute { int location; datatype type; int length; }; typedef hash_store< shash64, attribute > attribute_map; struct texture_tag {}; struct buffer_tag {}; struct program_tag {}; typedef handle< uint32, 16, 16, buffer_tag > buffer; typedef handle< uint32, 16, 16, texture_tag > texture; typedef handle< uint32, 16, 16, program_tag > program; NV_RTTI_DECLARE_NAME( buffer, "buffer" ) NV_RTTI_DECLARE_NAME( texture, "texture" ) NV_RTTI_DECLARE_NAME( program, "program" ) struct sampler { enum filter { LINEAR, NEAREST, NEAREST_MIPMAP_NEAREST, LINEAR_MIPMAP_NEAREST, NEAREST_MIPMAP_LINEAR, LINEAR_MIPMAP_LINEAR }; enum wrap { CLAMP_TO_EDGE, CLAMP_TO_BORDER, MIRRORED_REPEAT, REPEAT }; filter filter_min; filter filter_max; wrap wrap_s; wrap wrap_t; sampler() : filter_min( LINEAR ), filter_max( LINEAR ), wrap_s( REPEAT ), wrap_t( REPEAT ) {} sampler( filter min, filter max, wrap s, wrap t ) : filter_min( min ), filter_max( max ), wrap_s( s ), wrap_t( t ) {} sampler( filter f, wrap w ) : filter_min( f ), filter_max( f ), wrap_s( w ), wrap_t( w ) {} }; enum buffer_hint { STATIC_DRAW, STREAM_DRAW, DYNAMIC_DRAW }; enum buffer_type { VERTEX_BUFFER, INDEX_BUFFER, UNIFORM_BUFFER, TEXTURE_BUFFER, }; struct buffer_info { buffer_type type; buffer_hint hint; size_t size; }; struct texture_info { texture_type type; ivec3 size; image_format format; sampler tsampler; }; struct vertex_buffer_attribute { buffer vbuffer; datatype dtype; size_t components; size_t offset; size_t stride; slot location; bool owner; }; struct program_info { attribute_map* m_attribute_map; uniform_map* m_uniform_map; engine_uniform_list* m_engine_uniforms; }; class device { friend class context; public: device() { initialize_engine_uniforms(); } virtual program create_program( string_view vs_source, string_view fs_source ) = 0; virtual buffer create_buffer( buffer_type type, buffer_hint hint, size_t size, const void* source = nullptr ) = 0; virtual texture create_texture( texture_type type, ivec2 size, image_format aformat, sampler asampler, const void* data = nullptr ) = 0; virtual texture create_texture( texture_type type, ivec3 size, image_format aformat, sampler asampler, const void* data = nullptr ) = 0; virtual texture create_texture( texture_type type, pixel_format format ) = 0; // TODO: remove? virtual texture create_texture( ivec2 size, image_format aformat, sampler asampler, const void* data = nullptr ) { return create_texture( TEXTURE_2D, size, aformat, asampler, data ); } virtual void create_buffer( buffer, size_t, const void* = nullptr ) = 0; virtual image_data* create_image_data( string_view filename ) = 0; // temporary virtual image_data* create_image_data( const uint8* data, uint32 size ) = 0; // temporary virtual void release( texture ) = 0; virtual void release( buffer ) = 0; virtual void release( program ) = 0; virtual const texture_info* get_texture_info( texture ) const = 0; virtual const buffer_info* get_buffer_info( buffer ) const = 0; virtual string_view get_shader_header() const = 0; virtual texture create_texture( const image_data* data, sampler asampler ) { return create_texture( data->get_size(), data->get_format(), asampler, data->get_data() ); } int try_get_attribute_location( program p, const string_view& name ) const { return get_attribute_location( p, name, false ); } int try_get_block_location( program p, const string_view& name ) const { return get_block_location( p, name, false ); } virtual int get_attribute_location( program p, const string_view& name, bool fatal = true ) const = 0; virtual int get_block_location( program p, const string_view& name, bool fatal = true ) const = 0; virtual bool bind_block( program p, const string_view& name, uint32 index ) = 0; template < typename T > void set_uniform_array( program p, const string_view& name, const T* value, uint32 count, bool fatal = true ) { uniform_base* base = get_uniform( p, name, fatal ); if ( base != nullptr ) { if ( base->type_check( type_to_enum::type ) ) { // TODO: nicer check NV_ASSERT( static_cast( count ) <= base->get_length(), "LENGTH CHECK FAIL" ); static_cast< uniform* >( base )->set_value( value, count ); } } } template < typename T > void set_opt_uniform_array( program p, const string_view& name, const T* value, uint32 count ) { set_uniform_array( p, name, value, count, false ); } template < typename T > void set_opt_uniform_array( program p, const string_view& name, const array_view& value ) { set_uniform_array( p, name, value.data(), value.size(), false ); } template < typename T > void set_uniform( program p, const string_view& name, const T& value, bool fatal = true ) { uniform_base* base = get_uniform( p, name, fatal ); if ( base != nullptr ) { if ( base->type_check( type_to_enum::type ) ) { static_cast< uniform* >( base )->set_value( value ); } } } template < typename T > void set_opt_uniform( program p, const string_view& name, const T& value ) { set_uniform( p, name, value, false ); } virtual ~device() { destroy_engine_uniforms(); } // This is done this way to avoid compilation unit creation static engine_uniform_factory_map& get_uniform_factory() { static engine_uniform_factory_map s_engine_uniform_factory_map; return s_engine_uniform_factory_map; } // This is done this way to avoid compilation unit creation static engine_link_uniform_factory_map& get_link_uniform_factory() { static engine_link_uniform_factory_map s_engine_link_uniform_factory_map; return s_engine_link_uniform_factory_map; } virtual void prepare_program( program p ) = 0; protected: virtual uniform_base* get_uniform( program p, const string_view& name, bool fatal = true ) const = 0; void initialize_engine_uniforms() { engine_uniform_factory_map& factory_map = get_uniform_factory(); factory_map[ "nv_f_near"] = new engine_uniform_factory< engine_uniform_f_near >(); factory_map[ "nv_f_far"] = new engine_uniform_factory< engine_uniform_f_far >(); factory_map[ "nv_m_view" ] = new engine_uniform_factory< engine_uniform_m_view >(); factory_map[ "nv_m_view_inv" ] = new engine_uniform_factory< engine_uniform_m_view_inv >(); factory_map[ "nv_m_model" ] = new engine_uniform_factory< engine_uniform_m_model >(); factory_map[ "nv_m_model_inv" ] = new engine_uniform_factory< engine_uniform_m_model_inv >(); factory_map[ "nv_m_modelview" ] = new engine_uniform_factory< engine_uniform_m_modelview >(); factory_map[ "nv_m_modelview_inv" ] = new engine_uniform_factory< engine_uniform_m_modelview_inv >(); factory_map[ "nv_m_projection" ] = new engine_uniform_factory< engine_uniform_m_projection >(); factory_map[ "nv_m_projection_inv"] = new engine_uniform_factory< engine_uniform_m_projection_inv >(); factory_map[ "nv_m_normal" ] = new engine_uniform_factory< engine_uniform_m_normal >(); factory_map[ "nv_m_mvp" ] = new engine_uniform_factory< engine_uniform_m_mvp >(); factory_map[ "nv_m_mvp_inv"] = new engine_uniform_factory< engine_uniform_m_mvp_inv >(); factory_map[ "nv_v_camera_position" ] = new engine_uniform_factory< engine_uniform_v_camera_position >(); factory_map[ "nv_v_camera_direction" ] = new engine_uniform_factory< engine_uniform_v_camera_direction >(); factory_map[ "nv_v_viewport" ] = new engine_uniform_factory< engine_uniform_v_viewport >(); factory_map[ "nv_v_screen_size" ] = new engine_uniform_factory< engine_uniform_v_screen_size >(); engine_link_uniform_factory_map& factory_link_map = get_link_uniform_factory(); factory_link_map[ "nv_texture_0" ] = new engine_link_uniform_int<0>(); factory_link_map[ "nv_texture_1" ] = new engine_link_uniform_int<1>(); factory_link_map[ "nv_texture_2" ] = new engine_link_uniform_int<2>(); factory_link_map[ "nv_texture_3" ] = new engine_link_uniform_int<3>(); factory_link_map[ "nv_texture_4" ] = new engine_link_uniform_int<4>(); factory_link_map[ "nv_texture_5" ] = new engine_link_uniform_int<5>(); factory_link_map[ "nv_texture_6" ] = new engine_link_uniform_int<6>(); factory_link_map[ "nv_texture_7" ] = new engine_link_uniform_int<7>(); factory_link_map[ "nv_t_diffuse" ] = new engine_link_uniform_int(); factory_link_map[ "nv_t_normal" ] = new engine_link_uniform_int(); factory_link_map[ "nv_t_metallic" ] = new engine_link_uniform_int(); factory_link_map[ "nv_t_specular" ] = new engine_link_uniform_int(); factory_link_map[ "nv_t_roughness"] = new engine_link_uniform_int(); factory_link_map[ "nv_t_gloss" ] = new engine_link_uniform_int(); factory_link_map[ "nv_t_emissive" ] = new engine_link_uniform_int(); } void destroy_engine_uniforms() { for ( auto& i : get_uniform_factory() ) delete i.second; for ( auto& i : get_link_uniform_factory() ) delete i.second; get_uniform_factory().clear(); get_link_uniform_factory().clear(); } }; } // namespace nv #endif // NV_INTERFACE_DEVICE_HH