@ -7,30 +7,38 @@ function schedule_draw(state, context) {
@@ -7,30 +7,38 @@ function schedule_draw(state, context) {
}
}
function upload _if _needed ( context ) {
const gl = context . gl ;
if ( context . need _static _allocate ) {
if ( config . debug _print ) console . debug ( 'static allocate' ) ;
gl . bufferData ( gl . ARRAY _BUFFER , context . static _serializer . size , gl . DYNAMIC _DRAW ) ;
context . need _static _allocate = false ;
context . static _upload _from = 0 ;
context . need _static _upload = true ;
function upload _if _needed ( gl , buffer _kind , serializer ) {
if ( serializer . need _gpu _allocate ) {
if ( config . debug _print ) console . debug ( 'gpu allocate' ) ;
gl . bufferData ( buffer _kind , serializer . size , gl . DYNAMIC _DRAW ) ;
serializer . need _gpu _allocate = false ;
serializer . gpu _upload _from = 0 ;
}
if ( context . need _static _upload ) {
if ( config . debug _print ) console . debug ( 'static upload' ) ;
const upload _offset = context . static _upload _from ;
const upload _size = context . static _serializer . offset - upload _offset ;
gl . bufferSubData ( gl . ARRAY _BUFFER , upload _offset , new Uint8Array ( context . static _serializer . buffer , upload _offset , upload _size ) ) ;
context . need _static _upload = false ;
context . static _upload _from = context . static _serializer . offset ;
if ( serializer . gpu _upload _from < serializer . offset ) {
if ( config . debug _print ) console . debug ( 'gpu upload' ) ;
const upload _offset = serializer . gpu _upload _from ;
const upload _size = serializer . offset - upload _offset ;
gl . bufferSubData ( buffer _kind , upload _offset , new Uint8Array ( serializer . buffer , upload _offset , upload _size ) ) ;
serializer . gpu _upload _from = serializer . offset ;
}
}
function draw ( state , context ) {
const cpu _before = performance . now ( ) ;
let lod _level = - 1 ;
for ( let i = context . lods . length - 1 ; i >= 0 ; -- i ) {
const level = context . lods [ i ] ;
if ( state . canvas . zoom <= level . max _zoom ) {
lod _level = i ;
break ;
}
}
const lod = context . lods [ lod _level ] ;
state . timers . raf = false ;
const gl = context . gl ;
@ -43,122 +51,81 @@ function draw(state, context) {
@@ -43,122 +51,81 @@ function draw(state, context) {
query = gl . createQuery ( ) ;
gl . beginQuery ( context . gpu _timer _ext . TIME _ELAPSED _EXT , query ) ;
}
let locations ;
let buffers ;
buffers = context . buffers [ 'sdf' ] ;
gl . bindBuffer ( gl . ARRAY _BUFFER , buffers [ 'b_packed_static' ] ) ;
gl . bindBuffer ( gl . ELEMENT _ARRAY _BUFFER , buffers [ 'b_packed_static_index' ] ) ;
upload _if _needed ( context ) ;
gl . viewport ( 0 , 0 , context . canvas . width , context . canvas . height ) ;
gl . clearColor ( context . bgcolor . r , context . bgcolor . g , context . bgcolor . b , 1 ) ;
gl . clearDepth ( 0.0 ) ;
gl . clear ( gl . COLOR _BUFFER _BIT | gl . DEPTH _BUFFER _BIT ) ;
let index _count ;
const do _clip = true ; //(state.canvas.zoom > config.clip_zoom_threshold);
const before _clip = performance . now ( ) ;
const index _count = bvh _clip ( state , context , lod _level ) ;
const after _clip = performance . now ( ) ;
if ( do _clip ) {
context . need _index _upload = true ;
}
gl . bindBuffer ( gl . ARRAY _BUFFER , lod . data _buffer ) ;
gl . bindBuffer ( gl . ELEMENT _ARRAY _BUFFER , lod . index _buffer ) ;
if ( do _clip || context . need _index _upload ) {
const before _clip = performance . now ( ) ;
index _count = bvh _clip ( state , context ) ;
const after _clip = performance . now ( ) ;
}
if ( ! do _clip && ! context . need _index _upload ) {
index _count = context . full _index _count ;
}
upload _if _needed ( gl , gl . ARRAY _BUFFER , lod . vertices ) ;
upload _if _needed ( gl , gl . ELEMENT _ARRAY _BUFFER , lod . indices ) ;
document . getElementById ( 'debug-stats' ) . innerHTML = `
< span > Segments onscreen : $ { do _clip ? index _count : '-' } < / s p a n >
< span > LOD level : $ { lod _level } < / s p a n >
< span > Segments onscreen : $ { index _count } < / s p a n >
< span > Canvas offset : ( $ { state . canvas . offset . x } , $ { state . canvas . offset . y } ) < / s p a n >
< span > Canvas zoom : $ { Math . round ( state . canvas . zoom * 100000 ) / 100000 } < / s p a n > ` ;
if ( index _count > 0 ) {
const index _buffer = new Uint32Array ( state . onscreen _segments . buffer , 0 , index _count ) ;
const static _points = context . static _serializer . offset / config . bytes _per _point ;
//const dynamic_points = context.dynamic_serializer.offset / config.bytes_per_point;
if ( ! do _clip ) {
// Almost everything on screen anyways. Only upload indices once
if ( context . need _index _upload ) {
context . full _index _count = index _count ;
gl . bufferData ( gl . ELEMENT _ARRAY _BUFFER , index _buffer , gl . STATIC _DRAW ) ;
context . need _index _upload = false ;
}
}
if ( static _points > 0 ) {
// DEPTH PREPASS
if ( state . debug . do _prepass && do _clip ) {
gl . drawBuffers ( [ gl . NONE ] ) ;
locations = context . locations [ 'sdf' ] . opaque ;
gl . useProgram ( context . programs [ 'sdf' ] . opaque ) ;
gl . uniform2f ( locations [ 'u_res' ] , context . canvas . width , context . canvas . height ) ;
gl . uniform2f ( locations [ 'u_scale' ] , state . canvas . zoom , state . canvas . zoom ) ;
gl . uniform2f ( locations [ 'u_translation' ] , state . canvas . offset . x , state . canvas . offset . y ) ;
gl . uniform1i ( locations [ 'u_stroke_count' ] , state . stroke _count ) ;
gl . enableVertexAttribArray ( locations [ 'a_pos' ] ) ;
gl . enableVertexAttribArray ( locations [ 'a_line' ] ) ;
gl . enableVertexAttribArray ( locations [ 'a_stroke_id' ] ) ;
gl . vertexAttribPointer ( locations [ 'a_pos' ] , 3 , gl . FLOAT , false , config . bytes _per _point , 0 ) ;
gl . vertexAttribPointer ( locations [ 'a_line' ] , 4 , gl . FLOAT , false , config . bytes _per _point , 4 * 3 ) ;
gl . vertexAttribIPointer ( locations [ 'a_stroke_id' ] , 1 , gl . INT , config . bytes _per _point , 4 * 3 + 4 * 4 + 4 ) ;
if ( do _clip ) {
index _buffer . reverse ( ) ;
gl . bufferData ( gl . ELEMENT _ARRAY _BUFFER , index _buffer , gl . DYNAMIC _DRAW ) ;
}
gl . drawElements ( gl . TRIANGLES , index _count , gl . UNSIGNED _INT , 0 ) ;
}
// MAIN PASS
gl . drawBuffers ( [ gl . BACK ] ) ;
// DEPTH PREPASS
if ( state . debug . do _prepass ) {
gl . drawBuffers ( [ gl . NONE ] ) ;
locations = context . locations [ 'sdf' ] . main ;
locations = context . locations [ 'sdf' ] . opaque ;
gl . useProgram ( context . programs [ 'sdf' ] . main ) ;
gl . useProgram ( context . programs [ 'sdf' ] . opaque ) ;
gl . uniform2f ( locations [ 'u_res' ] , context . canvas . width , context . canvas . height ) ;
gl . uniform2f ( locations [ 'u_scale' ] , state . canvas . zoom , state . canvas . zoom ) ;
gl . uniform2f ( locations [ 'u_translation' ] , state . canvas . offset . x , state . canvas . offset . y ) ;
gl . uniform1i ( locations [ 'u_stroke_count' ] , state . stroke _count ) ;
gl . uniform1i ( locations [ 'u_debug_mode' ] , state . debug . red ) ;
gl . enableVertexAttribArray ( locations [ 'a_pos' ] ) ;
gl . enableVertexAttribArray ( locations [ 'a_line' ] ) ;
gl . enableVertexAttribArray ( locations [ 'a_color' ] ) ;
gl . enableVertexAttribArray ( locations [ 'a_stroke_id' ] ) ;
gl . vertexAttribPointer ( locations [ 'a_pos' ] , 3 , gl . FLOAT , false , config . bytes _per _point , 0 ) ;
gl . vertexAttribPointer ( locations [ 'a_line' ] , 4 , gl . FLOAT , false , config . bytes _per _point , 4 * 3 ) ;
gl . vertexAttribPointer ( locations [ 'a_color' ] , 3 , gl . UNSIGNED _BYTE , true , config . bytes _per _point , 4 * 3 + 4 * 4 ) ;
gl . vertexAttribIPointer ( locations [ 'a_stroke_id' ] , 1 , gl . INT , config . bytes _per _point , 4 * 3 + 4 * 4 + 4 ) ;
if ( do _clip ) {
if ( state . debug . do _prepass ) {
index _buffer . reverse ( ) ;
}
gl . bufferData ( gl . ELEMENT _ARRAY _BUFFER , index _buffer , gl . DYNAMIC _DRAW ) ;
}
gl . drawElements ( gl . TRIANGLES , index _count , gl . UNSIGNED _INT , 0 ) ;
}
// MAIN PASS
gl . drawBuffers ( [ gl . BACK ] ) ;
locations = context . locations [ 'sdf' ] . main ;
gl . useProgram ( context . programs [ 'sdf' ] . main ) ;
gl . uniform2f ( locations [ 'u_res' ] , context . canvas . width , context . canvas . height ) ;
gl . uniform2f ( locations [ 'u_scale' ] , state . canvas . zoom , state . canvas . zoom ) ;
gl . uniform2f ( locations [ 'u_translation' ] , state . canvas . offset . x , state . canvas . offset . y ) ;
gl . uniform1i ( locations [ 'u_stroke_count' ] , state . stroke _count ) ;
gl . uniform1i ( locations [ 'u_debug_mode' ] , state . debug . red ) ;
gl . enableVertexAttribArray ( locations [ 'a_pos' ] ) ;
gl . enableVertexAttribArray ( locations [ 'a_line' ] ) ;
gl . enableVertexAttribArray ( locations [ 'a_color' ] ) ;
gl . enableVertexAttribArray ( locations [ 'a_stroke_id' ] ) ;
gl . vertexAttribPointer ( locations [ 'a_pos' ] , 3 , gl . FLOAT , false , config . bytes _per _point , 0 ) ;
gl . vertexAttribPointer ( locations [ 'a_line' ] , 4 , gl . FLOAT , false , config . bytes _per _point , 4 * 3 ) ;
gl . vertexAttribPointer ( locations [ 'a_color' ] , 3 , gl . UNSIGNED _BYTE , true , config . bytes _per _point , 4 * 3 + 4 * 4 ) ;
gl . vertexAttribIPointer ( locations [ 'a_stroke_id' ] , 1 , gl . INT , config . bytes _per _point , 4 * 3 + 4 * 4 + 4 ) ;
//index_buffer.reverse();
gl . drawElements ( gl . TRIANGLES , index _count , gl . UNSIGNED _INT , 0 ) ;
}
/ *
// Dynamic data (stroke previews that are currently in progress)
const dynamic _points = context . dynamic _serializer . offset / config . bytes _per _point ;
@ -219,7 +186,7 @@ function draw(state, context) {
@@ -219,7 +186,7 @@ function draw(state, context) {
gl . drawElements ( gl . TRIANGLES , dynamic _indices . length , gl . UNSIGNED _INT , 0 ) ;
}
* /
if ( state . debug . draw _bvh ) {
const points = new Float32Array ( state . bvh . nodes . length * 6 * 2 ) ;
@ -259,7 +226,7 @@ function draw(state, context) {
@@ -259,7 +226,7 @@ function draw(state, context) {
gl . bufferData ( gl . ARRAY _BUFFER , points , gl . STATIC _DRAW ) ;
gl . drawArrays ( gl . TRIANGLES , 0 , points . length / 2 ) ;
}
if ( context . gpu _timer _ext ) {
gl . endQuery ( context . gpu _timer _ext . TIME _ELAPSED _EXT ) ;
@ -289,52 +256,7 @@ function draw(state, context) {
@@ -289,52 +256,7 @@ function draw(state, context) {
setTimeout ( next _tick , 0 ) ;
}
// Images
// locations = context.locations['image'];
// buffers = context.buffers['image'];
// textures = context.textures['image'];
// gl.useProgram(context.programs['image']);
// gl.enableVertexAttribArray(locations['a_pos']);
// gl.enableVertexAttribArray(locations['a_texcoord']);
// gl.uniform2f(locations['u_res'], context.canvas.width, context.canvas.height);
// gl.uniform2f(locations['u_scale'], state.canvas.zoom, state.canvas.zoom);
// gl.uniform2f(locations['u_translation'], state.canvas.offset.x, state.canvas.offset.y);
// gl.uniform1i(locations['u_texture'], 0);
// if (context.quad_positions_f32.byteLength > 0) {
// gl.bindBuffer(gl.ARRAY_BUFFER, buffers['b_pos']);
// gl.vertexAttribPointer(locations['a_pos'], 2, gl.FLOAT, false, 0, 0);
// gl.bufferData(gl.ARRAY_BUFFER, context.quad_positions_f32, gl.STATIC_DRAW);
// gl.bindBuffer(gl.ARRAY_BUFFER, buffers['b_texcoord']);
// gl.vertexAttribPointer(locations['a_texcoord'], 2, gl.FLOAT, false, 0, 0);
// gl.bufferData(gl.ARRAY_BUFFER, context.quad_texcoords_f32, gl.STATIC_DRAW);
// }
// const count = Object.keys(textures).length;
// let active_image_index = -1;
// gl.uniform1i(locations['u_outline'], 0);
// for (let key = 0; key < count; ++key) {
// if (textures[key].image_id === context.active_image) {
// active_image_index = key;
// continue;
// }
// gl.bindTexture(gl.TEXTURE_2D, textures[key].texture);
// gl.drawArrays(gl.TRIANGLES, key * 6, 6);
// }
// if (active_image_index !== -1) {
// gl.uniform1i(locations['u_outline'], 1);
// gl.bindTexture(gl.TEXTURE_2D, textures[active_image_index].texture);
// gl.drawArrays(gl.TRIANGLES, active_image_index * 6, 6);
// }
//
const cpu _after = performance . now ( ) ;