import { assert } from './auxiliaries' ; import { Context } from './context' ; import { WEBGL1_EXTENSIONS , WEBGL2_EXTENSIONS } from './extensions' ; export class ExtensionsHash { protected static readonly WEBGL_BACKENDS : Array < string > = [ 'webgl1' , 'webgl2' ] ; protected static readonly WEBGL_EXTENSIONS_BY_BACKEND = new Map < number , Array < string > > ( [ [ 0 , WEBGL1_EXTENSIONS ] , [ 1 , WEBGL2_EXTENSIONS ] , ] ) ; /**
     * All known WebGL extensions (regardless of WebGL version). When new extensions become known, a new internal
     * version has to be created, comprising all extensions again (some removed, some added w.r.t. previous versions).
     */ protected static readonly EXTENSIONS_BY_VERSION = new Map < number , Array < string > > ( [ [ 0b000 , [ 'ANGLE_instanced_arrays' , 'EXT_blend_minmax' , 'EXT_color_buffer_float' , 'EXT_color_buffer_half_float' , 'EXT_disjoint_timer_query' , 'EXT_disjoint_timer_query_webgl2' , 'EXT_frag_depth' , 'EXT_shader_texture_lod' , 'EXT_sRGB' , 'EXT_texture_filter_anisotropic' , 'OES_element_index_uint' , 'OES_standard_derivatives' , 'OES_texture_float' , 'OES_texture_float_linear' , 'OES_texture_half_float' , 'OES_texture_half_float_linear' , 'OES_vertex_array_object' , 'WEBGL_color_buffer_float' , 'WEBGL_compressed_texture_astc' , 'WEBGL_compressed_texture_atc' , 'WEBGL_compressed_texture_etc' , 'WEBGL_compressed_texture_etc1' , 'WEBGL_compressed_texture_pvrtc' , 'WEBGL_compressed_texture_s3tc' , 'WEBGL_compressed_texture_s3tc_srgb' , 'WEBGL_debug_renderer_info' , 'WEBGL_debug_shaders' , 'WEBGL_depth_texture' , 'WEBGL_draw_buffers' , 'WEBGL_lose_context' , ] ] , ] ) ; /**
     * Hash versioning is used to account for future, yet unknown/unpublished extensions while maintaining support for
     * existing hashes.
     */ protected static readonly LATEST_VERSION = 0b000 ; protected static readonly BASE64_ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-+' ; param base64 protected static encode64 ( bitfield ) { assert ( bitfield >= 0b000000 && bitfield <= 0b111111 , `expected bitfield in range [ 0b000000, 0b111111 ], given ${ bitfield }` ) ; return ExtensionsHash . BASE64_ALPHABET [ bitfield ] ; } param base64 protected static decode64 ( base64 ) { assert ( base64 . length === 1 , `expected single base64 character, given '${ base64 }'` ) ; const bitfield = ExtensionsHash . BASE64_ALPHABET . indexOf ( base64 ) ; assert ( bitfield > - 1 , `unknown base64 character, given '${ base64 }'` ) ; return bitfield ; } param backend param supported static encode ( backend , supported ) { const version = ExtensionsHash . LATEST_VERSION ; const extensions = ExtensionsHash . EXTENSIONS_BY_VERSION . get ( version ) as Array < string > ; const backendIndex = ExtensionsHash . WEBGL_BACKENDS . indexOf ( backend ) ; assert ( backendIndex > - 1 , `expected valid backend ${ ExtensionsHash . WEBGL_BACKENDS }, given ${ backend } ` ) ; let hash = ExtensionsHash . encode64 ( ( version << 3 ) | ( backendIndex + 1 ) ) ; if ( supported . length === 0 ) { return hash ; } let support = 0b000000 ; for ( let i = 0 ; i < extensions . length ; ++ i ) { support |= ( supported . indexOf ( extensions [ i ] ) > - 1 ? 0b100000 >> ( i % 6 ) : 0b0 ) ; if ( i % 6 < 5 && i < extensions . length - 1 ) { continue ; } hash += ExtensionsHash . encode64 ( support ) ; support = 0b000000 ; } return hash ; } param hash returns static decode ( hash ) { const hashHead = ExtensionsHash . decode64 ( hash [ 0 ] ) ; const version = hashHead >> 3 ; const backendIndex = ( hashHead & 0b000111 ) - 1 ; assert ( backendIndex < ExtensionsHash . WEBGL_BACKENDS . length , `expected valid backend index, given ${ backendIndex }` ) ; const backend = ExtensionsHash . WEBGL_BACKENDS [ backendIndex ] ; assert ( ExtensionsHash . EXTENSIONS_BY_VERSION . has ( version ) , `expected valid hash version, given ${ version }` ) ; const extensions = ExtensionsHash . EXTENSIONS_BY_VERSION . get ( version ) as Array < string > ; const expectedHashLength = Math . ceil ( extensions . length / 6 ) + 1 ; assert ( hash . length === expectedHashLength , `expected hash of version ${ version } to have a length of ${ expectedHashLength }, given ${ hash }` ) ; const strived = new Array < string > ( ) ; for ( let i = 1 ; i < hash . length ; ++ i ) { const bitfield = ExtensionsHash . decode64 ( hash [ i ] ) ; const offset = ( i - 1 ) * 6 ; if ( bitfield & 0b100000 ) { strived . push ( extensions [ offset + 0 ] ) ; } if ( bitfield & 0b010000 ) { strived . push ( extensions [ offset + 1 ] ) ; } if ( bitfield & 0b001000 ) { strived . push ( extensions [ offset + 2 ] ) ; } if ( bitfield & 0b000100 ) { strived . push ( extensions [ offset + 3 ] ) ; } if ( bitfield & 0b000010 ) { strived . push ( extensions [ offset + 4 ] ) ; } if ( bitfield & 0b000001 ) { strived . push ( extensions [ offset + 5 ] ) ; } } return [ backend , strived ] ; } param backend param extensions static complement ( backend , extensions ) { const backendIndex = ExtensionsHash . WEBGL_BACKENDS . indexOf ( backend ) ; assert ( backendIndex > - 1 , `expected valid backend ${ ExtensionsHash . WEBGL_BACKENDS }, given ${ backend } ` ) ; const webglExtensions = ExtensionsHash . WEBGL_EXTENSIONS_BY_BACKEND . get ( backendIndex ) as Array < string > ; return webglExtensions . filter ( ( ext ) => extensions . indexOf ( ext ) < 0 ) ; } }