// 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 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, }; enum texture_slot { TEX_DIFFUSE = 0, TEX_SPECULAR = 1, TEX_NORMAL = 2, TEXTURE_0 = 0, TEXTURE_1 = 1, TEXTURE_2 = 2, TEXTURE_3 = 3, TEXTURE_4 = 4, TEXTURE_5 = 5, TEXTURE_6 = 6, TEXTURE_7 = 7, }; struct attribute { std::string name; int location; datatype type; int length; }; typedef unordered_map< std::string, 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; 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 ) {} }; struct buffer_info { buffer_type type; buffer_hint hint; size_t size; }; struct texture_info { texture_type type; ivec2 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_ref vs_source, string_ref 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, void* data = nullptr ) = 0; // TODO: remove? virtual texture create_texture( ivec2 size, image_format aformat, sampler asampler, void* data = nullptr ) { return create_texture( TEXTURE_2D, size, aformat, asampler, data ); } virtual image_data* create_image_data( string_ref 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 const std::string& get_shader_header() const = 0; virtual texture create_texture( image_data* data, sampler asampler ) { return create_texture( data->get_size(), data->get_format(), asampler, (void*)data->get_data() ); } int try_get_attribute_location( program p, const std::string& name ) const { return get_attribute_location( p, name, false ); } virtual int get_attribute_location( program p, const std::string& name, bool fatal = true ) const = 0; template < typename T > void set_uniform_array( program p, const std::string& 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( (int)count <= base->get_length(), "LENGTH CHECK FAIL" ); ((uniform*)( base ))->set_value( value, count ); } } } template < typename T > void set_opt_uniform_array( program p, const std::string& 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 std::string& name, const const_array_ref& value ) { set_uniform_array( p, name, (const T*)value.data(), value.size(), false ); } template < typename T > void set_uniform( program p, const std::string& 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 ) ) { ((uniform*)( base ))->set_value( value ); } } } template < typename T > void set_opt_uniform( program p, const std::string& 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 std::string& name, bool fatal = true ) const = 0; void initialize_engine_uniforms() { engine_uniform_factory_map& factory_map = get_uniform_factory(); 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_projection" ] = new engine_uniform_factory< engine_uniform_m_projection >(); 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_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<0>(); factory_link_map[ "nv_t_specular"] = new engine_link_uniform_int<1>(); factory_link_map[ "nv_t_normal" ] = new engine_link_uniform_int<2>(); } 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