@ -1,10 +1,11 @@
let programs = { } ;
let programs = { } ;
let buffers = { } ;
let buffers = { } ;
let textures = { } ;
let timers = { } ;
let timers = { } ;
let config = {
let config = {
bytes _per _quad : 20 ,
bytes _per _quad : 28 ,
w : 24 ,
w : 3 2,
h : 24 ,
h : 3 2,
predefined _colors : {
predefined _colors : {
'Np' : [ 75 , 62 , 143 ] ,
'Np' : [ 75 , 62 , 143 ] ,
@ -25,6 +26,7 @@ let config = {
limit : - 1 ,
limit : - 1 ,
zoom _delta : 0.05 ,
zoom _delta : 0.05 ,
raster _texture _size : 4096 ,
} ;
} ;
let canvas = null ;
let canvas = null ;
@ -38,39 +40,58 @@ let zoom_level = 0;
let zoom _screenp = { 'x' : 0 , 'y' : 0 } ;
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 } ;
const tquad _vs _src = ` #version 300 es
const tquad _vs _src = ` #version 300 es
in vec2 a _pos ;
in vec2 a _pos ;
in vec2 a _size ;
in vec2 a _size ;
in vec4 a _color ;
in vec4 a _color ;
in vec2 a _uv ;
uniform vec2 u _res ;
uniform vec2 u _res ;
uniform vec2 u _translation ;
uniform vec2 u _translation ;
uniform float u _scale ;
uniform float u _scale ;
uniform vec2 u _textile ;
uniform vec2 u _tile ;
out vec4 v _color ;
out vec4 v _color ;
out vec2 v _uv ;
void main ( ) {
void main ( ) {
int vertex _index = gl _VertexID % 6 ;
int vertex _index = gl _VertexID % 6 ;
vec2 corner ;
vec2 corner ;
vec2 uv ;
vec2 inset = vec2 ( 1.0 ) ;
// "Fix" for zero-width stages
if ( a _size . x < 0.1 ) {
inset = vec2 ( 0.0 ) ;
}
vec2 cycles = a _size / u _tile ;
if ( vertex _index == 0 ) {
if ( vertex _index == 0 ) {
// "top left" aka "p1"
// "top left" aka "p1"
corner = a _pos ;
corner = a _pos + inset ;
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 ( a _size . x , 0 ) + vec2 ( - inset . x , inset . y ) ;
uv = a _uv + vec2 ( u _textile . x * cycles . 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 , a _size . y ) + vec2 ( inset . x , - inset . y ) ;
uv = a _uv + vec2 ( 0 , u _textile . y * cycles . y ) ;
} else {
} else {
// "bottom right" aka "p4"
// "bottom right" aka "p4"
corner = a _pos + a _size ;
corner = a _pos + a _size - inset ;
uv = a _uv + u _textile * cycles ;
}
}
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 ;
screen02 . y = 2.0 - screen02 . y ;
screen02 . y = 2.0 - screen02 . y ;
v _color = a _color ;
v _color = a _color ;
v _uv = uv - u _textile * vec2 ( 0.2 ) ;
gl _Position = vec4 ( screen02 - 1.0 , 1.0 , 1.0 ) ;
gl _Position = vec4 ( screen02 - 1.0 , 1.0 , 1.0 ) ;
}
}
@ -80,11 +101,15 @@ const tquad_fs_src = `#version 300 es
precision highp float ;
precision highp float ;
in vec4 v _color ;
in vec4 v _color ;
in vec2 v _uv ;
uniform sampler2D u _texture ;
layout ( location = 0 ) out vec4 FragColor ;
layout ( location = 0 ) out vec4 FragColor ;
void main ( ) {
void main ( ) {
FragColor = v _color ;
vec4 text = texture ( u _texture , v _uv ) ;
FragColor = vec4 ( text . rgb * text . a + v _color . rgb * ( 1.0 - text . a ) , 1.0 ) ;
}
}
` ;
` ;
@ -129,28 +154,37 @@ function draw(ts, animation) {
gl . bufferSubData ( gl . ARRAY _BUFFER , 0 , quads . pos ) ;
gl . bufferSubData ( gl . ARRAY _BUFFER , 0 , quads . pos ) ;
gl . bufferSubData ( gl . ARRAY _BUFFER , quads . pos . byteLength , quads . size ) ;
gl . bufferSubData ( gl . ARRAY _BUFFER , quads . pos . byteLength , quads . size ) ;
gl . bufferSubData ( gl . ARRAY _BUFFER , quads . pos . byteLength + quads . size . byteLength , quads . color ) ;
gl . bufferSubData ( gl . ARRAY _BUFFER , quads . pos . byteLength + quads . size . byteLength , quads . color ) ;
gl . bufferSubData ( gl . ARRAY _BUFFER , quads . pos . byteLength + quads . size . byteLength + quads . color . byteLength , quads . uv ) ;
gl . uniform2f ( program . locations [ 'u_res' ] , canvas . width , canvas . height ) ;
gl . uniform2f ( program . locations [ 'u_res' ] , canvas . width , canvas . height ) ;
gl . uniform2f ( program . locations [ 'u_translation' ] , offset . x , offset . y ) ;
gl . uniform2f ( program . locations [ 'u_translation' ] , offset . x , offset . y ) ;
gl . uniform1f ( program . locations [ 'u_scale' ] , zoom ) ;
gl . uniform1f ( program . locations [ 'u_scale' ] , zoom ) ;
gl . uniform2f ( program . locations [ 'u_textile' ] , config . w / config . raster _texture _size , config . h / config . raster _texture _size ) ;
gl . uniform1i ( program . locations [ 'u_texture' ] , textures [ 'raster' ] ) ;
gl . uniform2f ( program . locations [ 'u_tile' ] , config . w , config . h ) ;
gl . enableVertexAttribArray ( program . locations [ 'a_pos' ] ) ;
gl . enableVertexAttribArray ( program . locations [ 'a_pos' ] ) ;
gl . enableVertexAttribArray ( program . locations [ 'a_size' ] ) ;
gl . enableVertexAttribArray ( program . locations [ 'a_size' ] ) ;
gl . enableVertexAttribArray ( program . locations [ 'a_color' ] ) ;
gl . enableVertexAttribArray ( program . locations [ 'a_color' ] ) ;
gl . enableVertexAttribArray ( program . locations [ 'a_uv' ] ) ;
gl . vertexAttribPointer ( program . locations [ 'a_pos' ] , 2 , gl . FLOAT , false , 2 * 4 , 0 ) ;
gl . vertexAttribPointer ( program . locations [ 'a_pos' ] , 2 , gl . FLOAT , false , 2 * 4 , 0 ) ;
gl . vertexAttribPointer ( program . locations [ 'a_size' ] , 2 , gl . FLOAT , false , 2 * 4 , quads . pos . byteLength ) ;
gl . vertexAttribPointer ( program . locations [ 'a_size' ] , 2 , gl . FLOAT , false , 2 * 4 , quads . pos . byteLength ) ;
gl . vertexAttribPointer ( program . locations [ 'a_color' ] , 4 , gl . UNSIGNED _BYTE , true , 4 * 1 , quads . pos . byteLength + quads . size . byteLength ) ;
gl . vertexAttribPointer ( program . locations [ 'a_color' ] , 4 , gl . UNSIGNED _BYTE , true , 4 * 1 , quads . pos . byteLength + quads . size . byteLength ) ;
gl . vertexAttribPointer ( program . locations [ 'a_uv' ] , 2 , gl . FLOAT , false , 2 * 4 , quads . pos . byteLength + quads . size . byteLength + quads . color . byteLength ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_pos' ] , 1 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_pos' ] , 1 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_size' ] , 1 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_size' ] , 1 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_color' ] , 1 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_color' ] , 1 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_uv' ] , 1 ) ;
gl . bindTexture ( gl . TEXTURE _2D , textures [ 'raster' ] ) ;
gl . drawArraysInstanced ( gl . TRIANGLES , 0 , 6 , quads . count ) ;
gl . drawArraysInstanced ( gl . TRIANGLES , 0 , 6 , quads . 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 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_color' ] , 0 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_color' ] , 0 ) ;
gl . vertexAttribDivisor ( program . locations [ 'a_uv' ] , 0 ) ;
}
}
if ( gpu _timer _ext ) {
if ( gpu _timer _ext ) {
@ -227,6 +261,17 @@ function init_webgl() {
'b_packed' : gl . createBuffer ( ) ,
'b_packed' : gl . createBuffer ( ) ,
} ;
} ;
textures = {
'raster' : gl . createTexture ( ) ,
} ;
const zeroes = new Uint8Array ( config . raster _texture _size * config . raster _texture _size * 4 ) ;
gl . bindTexture ( gl . TEXTURE _2D , textures [ 'raster' ] ) ;
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 ] ;