@ -29,6 +29,7 @@ let config = {
zoom _delta : 0.05 ,
zoom _delta : 0.05 ,
raster _texture _size : 4096 ,
raster _texture _size : 4096 ,
max _zoom _level : 0 ,
max _zoom _level : 0 ,
show _texture : false ,
} ;
} ;
let canvas = null ;
let canvas = null ;
@ -43,7 +44,9 @@ let zoom_screenp = { 'x': 0, 'y': 0 };
let last _frame _dt = 0 ;
let last _frame _dt = 0 ;
let last _frame _ts = 0 ;
let last _frame _ts = 0 ;
let raster _tile = { 'x' : 0 , 'y' : 0 } ;
let raster _tile = { 'x' : 0 , 'y' : 0 } ;
let number _tile = { 'x' : 0 , 'y' : 0 } ;
let spacedown = false ;
let spacedown = false ;
let numbers _rasterized = 0 ;
const tquad _vs _src = ` #version 300 es
const tquad _vs _src = ` #version 300 es
in vec2 a _pos ;
in vec2 a _pos ;
@ -56,6 +59,7 @@ const tquad_vs_src = `#version 300 es
uniform float u _scale ;
uniform float u _scale ;
uniform vec2 u _textile ;
uniform vec2 u _textile ;
uniform vec2 u _tile ;
uniform vec2 u _tile ;
uniform int u _single ;
out vec4 v _color ;
out vec4 v _color ;
out vec2 v _uv ;
out vec2 v _uv ;
@ -72,7 +76,11 @@ const tquad_vs_src = `#version 300 es
}
}
vec2 cycles = a _size / u _tile ;
vec2 cycles = a _size / u _tile ;
vec2 tt = u _textile / u _tile ;
vec2 size = a _size ;
if ( u _single != 0 ) {
size = u _tile ;
}
if ( vertex _index == 0 ) {
if ( vertex _index == 0 ) {
// "top left" aka "p1"
// "top left" aka "p1"
@ -80,16 +88,16 @@ const tquad_vs_src = `#version 300 es
uv = a _uv ;
uv = a _uv ;
} else if ( vertex _index == 1 || vertex _index == 5 ) {
} else if ( vertex _index == 1 || vertex _index == 5 ) {
// "top right" aka "p2"
// "top right" aka "p2"
corner = a _pos + vec2 ( a _ size. x , 0 ) ;
corner = a _pos + vec2 ( size . x , 0 ) ;
uv = a _uv + vec2 ( u _textile . x * cycles . x , 0 ) ;
uv = a _uv + vec2 ( u _textile . x , 0 ) ;
} else if ( vertex _index == 2 || vertex _index == 4 ) {
} else if ( vertex _index == 2 || vertex _index == 4 ) {
// "bottom left" aka "p3"
// "bottom left" aka "p3"
corner = a _pos + vec2 ( 0 , a _ size. y ) ;
corner = a _pos + vec2 ( 0 , size . y ) ;
uv = a _uv + vec2 ( 0 , u _textile . y * cycles . y ) ;
uv = a _uv + vec2 ( 0 , u _textile . y ) ;
} else {
} else {
// "bottom right" aka "p4"
// "bottom right" aka "p4"
corner = a _pos + a _ size;
corner = a _pos + size ;
uv = a _uv + u _textile * cycles ;
uv = a _uv + u _textile ;
}
}
vec2 screen02 = ( corner . xy * vec2 ( u _scale ) + u _translation ) / u _res * 2.0 ;
vec2 screen02 = ( corner . xy * vec2 ( u _scale ) + u _translation ) / u _res * 2.0 ;
@ -109,13 +117,18 @@ const tquad_fs_src = `#version 300 es
uniform sampler2D u _texture ;
uniform sampler2D u _texture ;
uniform float u _fade ;
uniform float u _fade ;
uniform int u _solid ;
layout ( location = 0 ) out vec4 FragColor ;
layout ( location = 0 ) out vec4 FragColor ;
void main ( ) {
void main ( ) {
if ( u _solid != 0 ) {
FragColor = vec4 ( v _color . rgb * v _color . a , v _color . a ) ;
} else {
vec4 text = texture ( u _texture , v _uv ) ;
vec4 text = texture ( u _texture , v _uv ) ;
text . a = min ( min ( text . a , v _color . a ) , u _fade ) ;
float a = min ( u _fade , min ( text . a , v _color . a ) ) ;
FragColor = vec4 ( text . rgb * text . a + v _color . rgb , 1.0 ) ;
FragColor = vec4 ( text . rgb * a , a ) ;
}
}
}
` ;
` ;
@ -177,6 +190,8 @@ function draw(ts, animation) {
gl . uniform1i ( program . locations [ 'u_texture' ] , textures [ 'raster' ] ) ;
gl . uniform1i ( program . locations [ 'u_texture' ] , textures [ 'raster' ] ) ;
gl . uniform2f ( program . locations [ 'u_tile' ] , config . w , config . h ) ;
gl . uniform2f ( program . locations [ 'u_tile' ] , config . w , config . h ) ;
gl . uniform1f ( program . locations [ 'u_fade' ] , fade ) ;
gl . uniform1f ( program . locations [ 'u_fade' ] , fade ) ;
gl . uniform1i ( program . locations [ 'u_solid' ] , 1 ) ;
gl . uniform1i ( program . locations [ 'u_single' ] , 0 ) ;
gl . enableVertexAttribArray ( program . locations [ 'a_pos' ] ) ;
gl . enableVertexAttribArray ( program . locations [ 'a_pos' ] ) ;
gl . enableVertexAttribArray ( program . locations [ 'a_size' ] ) ;
gl . enableVertexAttribArray ( program . locations [ 'a_size' ] ) ;
@ -193,8 +208,14 @@ function draw(ts, animation) {
gl . vertexAttribDivisor ( program . locations [ 'a_color' ] , 1 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_color' ] , 1 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_uv' ] , 1 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_uv' ] , 1 ) ;
gl . drawArraysInstanced ( gl . TRIANGLES , 0 , 6 , clipped . count ) ;
if ( fade > 0 ) {
gl . bindTexture ( gl . TEXTURE _2D , textures [ 'raster' ] ) ;
gl . bindTexture ( gl . TEXTURE _2D , textures [ 'raster' ] ) ;
gl . uniform1i ( program . locations [ 'u_solid' ] , 0 ) ;
gl . uniform1i ( program . locations [ 'u_single' ] , 1 ) ;
gl . drawArraysInstanced ( gl . TRIANGLES , 0 , 6 , clipped . count ) ;
gl . drawArraysInstanced ( gl . TRIANGLES , 0 , 6 , clipped . count ) ;
}
gl . vertexAttribDivisor ( program . locations [ 'a_pos' ] , 0 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_pos' ] , 0 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_size' ] , 0 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_size' ] , 0 ) ;
@ -278,8 +299,12 @@ function init_webgl() {
textures = {
textures = {
'raster' : gl . createTexture ( ) ,
'raster' : gl . createTexture ( ) ,
'numbers' : gl . createTexture ( ) ,
} ;
} ;
gl . enable ( gl . BLEND ) ;
gl . blendFunc ( gl . ONE , gl . ONE _MINUS _SRC _ALPHA ) ;
const zeroes = new Uint8Array ( config . raster _texture _size * config . raster _texture _size * 4 ) ;
const zeroes = new Uint8Array ( config . raster _texture _size * config . raster _texture _size * 4 ) ;
gl . bindTexture ( gl . TEXTURE _2D , textures [ 'raster' ] ) ;
gl . bindTexture ( gl . TEXTURE _2D , textures [ 'raster' ] ) ;
@ -287,6 +312,11 @@ function init_webgl() {
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _MAG _FILTER , gl . NEAREST ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _MAG _FILTER , gl . NEAREST ) ;
gl . texImage2D ( gl . TEXTURE _2D , 0 , gl . RGBA , config . raster _texture _size , config . raster _texture _size , 0 , gl . RGBA , gl . UNSIGNED _BYTE , zeroes ) ; // fill the whole texture once with zeroes to kill a warning about a partial upload
gl . texImage2D ( gl . TEXTURE _2D , 0 , gl . RGBA , config . raster _texture _size , config . raster _texture _size , 0 , gl . RGBA , gl . UNSIGNED _BYTE , zeroes ) ; // fill the whole texture once with zeroes to kill a warning about a partial upload
gl . bindTexture ( gl . TEXTURE _2D , textures [ 'numbers' ] ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _MIN _FILTER , gl . LINEAR ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _MAG _FILTER , gl . NEAREST ) ;
gl . texImage2D ( gl . TEXTURE _2D , 0 , gl . RGBA , config . raster _texture _size , config . raster _texture _size , 0 , gl . RGBA , gl . UNSIGNED _BYTE , zeroes ) ; // fill the whole texture once with zeroes to kill a warning about a partial upload
const resize _canvas = ( entries ) => {
const resize _canvas = ( entries ) => {
// https://www.khronos.org/webgl/wiki/HandlingHighDPI
// https://www.khronos.org/webgl/wiki/HandlingHighDPI
const entry = entries [ 0 ] ;
const entry = entries [ 0 ] ;