Browse Source

Fix dynamic data

ssao
A.Olokhtonov 11 months ago
parent
commit
72eedf9b48
  1. 25
      client/bvh.js
  2. 10
      client/client_recv.js
  3. 1
      client/index.html
  4. 7
      client/index.js
  5. 55
      client/webgl_draw.js
  6. 34
      client/webgl_geometry.js
  7. 10
      client/webgl_listeners.js
  8. 54
      client/webgl_shaders.js
  9. 2
      server/recv.js
  10. 2
      server/send.js

25
client/bvh.js

@ -1,5 +1,3 @@ @@ -1,5 +1,3 @@
// TODO: get rid of node_count
//
function bvh_make_leaf(bvh, index, stroke) {
const leaf = {
'stroke_index': index,
@ -100,15 +98,12 @@ function bvh_rotate(bvh, index) { @@ -100,15 +98,12 @@ function bvh_rotate(bvh, index) {
function bvh_add_stroke(bvh, index, stroke) {
const leaf_index = bvh_make_leaf(bvh, index, stroke);
if (bvh.node_count === 0) {
if (bvh.nodes.length === 1) {
bvh.root = leaf_index;
bvh.node_count++;
return;
}
bvh.node_count++;
if (bvh.pqueue.capacity < Math.ceil(bvh.node_count * 1.2)) {
if (bvh.pqueue.capacity < Math.ceil(bvh.nodes.length * 1.2)) {
bvh.pqueue = new MinQueue(bvh.pqueue.capacity * 2);
}
@ -152,8 +147,6 @@ function bvh_add_stroke(bvh, index, stroke) { @@ -152,8 +147,6 @@ function bvh_add_stroke(bvh, index, stroke) {
bvh.nodes[new_parent].bbox = new_bbox;
bvh.nodes[new_parent].area = (new_bbox.x2 - new_bbox.x1) * (new_bbox.y2 - new_bbox.y1);
bvh.node_count++;
// 3. Refit and rotate
let refit_index = bvh.nodes[leaf_index].parent_index;
while (refit_index !== null) {
@ -195,18 +188,8 @@ function bvh_intersect_quad(bvh, quad) { @@ -195,18 +188,8 @@ function bvh_intersect_quad(bvh, quad) {
}
function bvh_clip(state, context) {
if (state.onscreen_segments === null) {
let total_points = 0;
for (const event of state.events) {
if (event.type === EVENT.STROKE && !event.deleted && event.points.length > 0) {
total_points += event.points.length - 1;
}
}
if (total_points > 0) {
state.onscreen_segments = new Uint32Array(total_points * 6);
}
if (state.onscreen_segments.length < Math.ceil(state.total_points * 6 * 1.2)) {
state.onscreen_segments = new Uint32Array(state.total_points * 6 * 2);
}
let at = 0;

10
client/client_recv.js

@ -170,10 +170,12 @@ function handle_event(state, context, event, options = {}) { @@ -170,10 +170,12 @@ function handle_event(state, context, event, options = {}) {
}
case EVENT.STROKE: {
if (event.user_id != state.me) {
// TODO: @speed do proper local prediction, it's not that hard
//if (event.user_id != state.me) {
geometry_clear_player(state, context, event.user_id);
need_draw = true;
}
//}
event.index = state.events.length;
event.starting_index = state.starting_index;
@ -182,6 +184,8 @@ function handle_event(state, context, event, options = {}) { @@ -182,6 +184,8 @@ function handle_event(state, context, event, options = {}) {
state.starting_index += (event.points.length - 1) * 4;
}
state.total_points += event.points.length;
geometry_add_stroke(state, context, event, state.events.length, options.skip_bvh === true);
state.stroke_count++;
@ -368,6 +372,8 @@ async function handle_message(state, context, d) { @@ -368,6 +372,8 @@ async function handle_message(state, context, d) {
}
}
state.sn = event_count;
bvh_construct(state);
document.getElementById('debug-render-from').max = state.stroke_count;

1
client/index.html

@ -41,7 +41,6 @@ @@ -41,7 +41,6 @@
<label><input type="checkbox" id="debug-red">Simple shader</label>
<label><input type="checkbox" id="debug-do-prepass">Depth prepass</label>
<label><input type="checkbox" id="debug-force-clip-off">Force clipping off</label>
<label><input type="checkbox" id="debug-draw-bvh">Draw BVH</label>
<div class="flexcol">

7
client/index.js

@ -1,6 +1,8 @@ @@ -1,6 +1,8 @@
// NEXT: pan with m3, place dot, cursor size and color, YELLOW and gray, show user cursor, background styles,
// view desks, undo, eraser, ruler, images (movable), quadtree for clipping, f5 without redownload, progress bar
//
// use returning ID on insert intead of (COLLIDING!) rand_32
// look into using u64 for point coordinates? fix bad drawings on zoomout
document.addEventListener('DOMContentLoaded', main);
@ -165,10 +167,10 @@ function main() { @@ -165,10 +167,10 @@ function main() {
'events': [],
'stroke_count': 0,
'starting_index': 0,
'total_points': 0,
'bvh': {
'nodes': [],
'node_count': 0,
'root': null,
'pqueue': new MinQueue(1024),
},
@ -189,7 +191,7 @@ function main() { @@ -189,7 +191,7 @@ function main() {
},
'players': {},
'onscreen_segments': null,
'onscreen_segments': new Uint32Array(1024),
'debug': {
'red': false,
@ -198,7 +200,6 @@ function main() { @@ -198,7 +200,6 @@ function main() {
'limit_to': false,
'render_from': 0,
'render_to': 0,
'force_clip_off': false,
'draw_bvh': false,
}
};

55
client/webgl_draw.js

@ -57,7 +57,7 @@ function draw(state, context) { @@ -57,7 +57,7 @@ function draw(state, context) {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
let index_count;
const do_clip = !state.debug.force_clip_off; //(state.canvas.zoom > config.clip_zoom_threshold);
const do_clip = true;//(state.canvas.zoom > config.clip_zoom_threshold);
if (do_clip) {
context.need_index_upload = true;
@ -137,6 +137,7 @@ function draw(state, context) { @@ -137,6 +137,7 @@ function draw(state, context) {
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.uniform1i(locations['u_shrink'], 1);
gl.enableVertexAttribArray(locations['a_pos']);
gl.enableVertexAttribArray(locations['a_line']);
@ -160,6 +161,34 @@ function draw(state, context) { @@ -160,6 +161,34 @@ function draw(state, context) {
}
}
// Dynamic data (stroke previews that are currently in progress)
const dynamic_points = context.dynamic_serializer.offset / config.bytes_per_point;
if (dynamic_points > 0) {
gl.clear(gl.DEPTH_BUFFER_BIT);
gl.bindBuffer(gl.ARRAY_BUFFER, buffers['b_packed_dynamic']);
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);
gl.uniform1i(locations['u_shrink'], 0);
if (context.need_dynamic_upload) {
gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(context.dynamic_serializer.buffer, 0, context.dynamic_serializer.offset), gl.DYNAMIC_DRAW);
context.need_dynamic_upload = false;
}
gl.drawArrays(gl.TRIANGLES, 0, dynamic_points);
}
if (state.debug.draw_bvh) {
const points = new Float32Array(state.bvh.nodes.length * 6 * 2);
@ -195,32 +224,10 @@ function draw(state, context) { @@ -195,32 +224,10 @@ function draw(state, context) {
gl.vertexAttribPointer(locations['a_pos'], 2, gl.FLOAT, false, 8, 0);
gl.clear(gl.DEPTH_BUFFER_BIT);
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
gl.drawArrays(gl.TRIANGLES, 0, points.length / 2);
}
/*
if (dynamic_points > 0) {
gl.bindBuffer(gl.ARRAY_BUFFER, buffers['b_packed_dynamic']);
gl.enableVertexAttribArray(locations['a_pos']);
gl.enableVertexAttribArray(locations['a_line']);
gl.enableVertexAttribArray(locations['a_color']);
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);
if (context.need_dynamic_upload) {
gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(context.dynamic_serializer.buffer, 0, context.dynamic_serializer.offset), gl.STATIC_DRAW);
context.need_dynamic_upload = false;
}
gl.drawArrays(gl.TRIANGLES, 0, dynamic_points);
}
*/
if (context.gpu_timer_ext) {
gl.endQuery(context.gpu_timer_ext.TIME_ELAPSED_EXT);

34
client/webgl_geometry.js

@ -13,18 +13,23 @@ function push_point(s, x, y, ax, ay, bx, by, thickness, r, g, b, stroke_id) { @@ -13,18 +13,23 @@ function push_point(s, x, y, ax, ay, bx, by, thickness, r, g, b, stroke_id) {
ser_u32(s, stroke_id);
}
function push_quad(s, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y, ax, ay, bx, by, thickness, r, g, b, stroke_id) {
push_point(s, p1x, p1y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
push_point(s, p2x, p2y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
push_point(s, p3x, p3y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
push_point(s, p4x, p4y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
function push_quad(s, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y, ax, ay, bx, by, thickness, r, g, b, stroke_id, indexed = true) {
if (indexed) {
push_point(s, p1x, p1y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
push_point(s, p2x, p2y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
push_point(s, p3x, p3y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
push_point(s, p4x, p4y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
} else {
push_point(s, p1x, p1y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
push_point(s, p2x, p2y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
push_point(s, p3x, p3y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
push_point(s, p4x, p4y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
push_point(s, p3x, p3y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
push_point(s, p2x, p2y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
}
}
function push_stroke(s, stroke, stroke_index) {
// if (stroke.stroke_id !== 1123776468) {
// return;
// }
function push_stroke(s, stroke, stroke_index, indexed = true) {
const stroke_width = stroke.width;
const points = stroke.points;
const color_u32 = stroke.color;
@ -73,7 +78,8 @@ function push_stroke(s, stroke, stroke_index) { @@ -73,7 +78,8 @@ function push_stroke(s, stroke, stroke_index) {
to.x, to.y,
stroke_width,
r, g, b,
stroke_index
stroke_index,
indexed
);
}
}
@ -97,7 +103,7 @@ function geometry_prepare_stroke(state) { @@ -97,7 +103,7 @@ function geometry_prepare_stroke(state) {
};
}
function geometry_add_stroke(state, context, stroke, stroke_index, skip_bvh) {
function geometry_add_stroke(state, context, stroke, stroke_index, skip_bvh = false) {
if (!state.online || !stroke || stroke.points.length === 0) return;
stroke.bbox = stroke_bbox(stroke);
@ -157,8 +163,8 @@ function recompute_dynamic_data(state, context) { @@ -157,8 +163,8 @@ function recompute_dynamic_data(state, context) {
for (const player_id in state.players) {
// player has the same data as their current stroke: points, color, width
const player = state.players[player_id];
if (player.points.length > 0) {
push_stroke(context.dynamic_serializer, player, 0); // TODO: stroke index ??
if (player.points.length > 1) {
push_stroke(context.dynamic_serializer, player, 0, false);
}
}

10
client/webgl_listeners.js

@ -26,7 +26,6 @@ function debug_panel_init(state, context) { @@ -26,7 +26,6 @@ function debug_panel_init(state, context) {
document.getElementById('debug-do-prepass').checked = state.debug.do_prepass;
document.getElementById('debug-limit-from').checked = state.debug.limit_from;
document.getElementById('debug-limit-to').checked = state.debug.limit_to;
document.getElementById('debug-force-clip-off').checked = state.debug.force_clip_off;
document.getElementById('debug-draw-bvh').checked = state.debug.draw_bvh;
document.getElementById('debug-draw-bvh').addEventListener('change', (e) => {
@ -34,11 +33,6 @@ function debug_panel_init(state, context) { @@ -34,11 +33,6 @@ function debug_panel_init(state, context) {
schedule_draw(state, context);
});
document.getElementById('debug-force-clip-off').addEventListener('change', (e) => {
state.debug.force_clip_off = e.target.checked;
schedule_draw(state, context);
});
document.getElementById('debug-red').addEventListener('change', (e) => {
state.debug.red = e.target.checked;
schedule_draw(state, context);
@ -257,9 +251,9 @@ function mouseup(e, state, context) { @@ -257,9 +251,9 @@ function mouseup(e, state, context) {
const stroke = geometry_prepare_stroke(state);
if (stroke) {
geometry_add_stroke(state, context, stroke, 0); // TODO: stroke index?
//geometry_add_stroke(state, context, stroke, 0); // TODO: stroke index?
queue_event(state, stroke_event(state));
geometry_clear_player(state, context, state.me);
//geometry_clear_player(state, context, state.me);
schedule_draw(state, context);
}

54
client/webgl_shaders.js

@ -113,6 +113,7 @@ const sdf_vs_src = `#version 300 es @@ -113,6 +113,7 @@ const sdf_vs_src = `#version 300 es
uniform vec2 u_translation;
uniform int u_stroke_count;
uniform int u_shrink;
out vec4 v_line;
out vec2 v_texcoord;
@ -123,31 +124,35 @@ const sdf_vs_src = `#version 300 es @@ -123,31 +124,35 @@ const sdf_vs_src = `#version 300 es
void main() {
vec2 screen01 = (a_pos.xy * u_scale + u_translation) / u_res;
vec2 screen02 = screen01 * 2.0;
// Inflate quad by 1 pixel
float apron = 2.0;
vec2 line_dir = normalize(a_line.zw - a_line.xy);
vec2 up_dir = vec2(line_dir.y, -line_dir.x);
vec2 pixel = vec2(2.0) / u_res * apron;
int vertex_index = gl_VertexID % 4;
if (vertex_index == 0) {
// "top left" aka "p1"
screen02 += up_dir * pixel - line_dir * pixel;
v_texcoord = a_pos.xy + up_dir * 1.0 / u_scale - line_dir * 1.0 / u_scale;
} else if (vertex_index == 1) {
// "top right" aka "p2"
screen02 += up_dir * pixel + line_dir * pixel;
v_texcoord = a_pos.xy + up_dir * 1.0 / u_scale + line_dir * 1.0 / u_scale;
} else if (vertex_index == 2) {
// "bottom left" aka "p3"
screen02 += -up_dir * pixel - line_dir * pixel;
v_texcoord = a_pos.xy - up_dir * 1.0 / u_scale - line_dir * 1.0 / u_scale;
if (u_shrink == 1) {
// Inflate quad by 2 pixels (change to 1 when I figure out how to fix the prepass shit)
float apron = 2.0;
vec2 line_dir = normalize(a_line.zw - a_line.xy);
vec2 up_dir = vec2(line_dir.y, -line_dir.x);
vec2 pixel = vec2(2.0) / u_res * apron;
int vertex_index = gl_VertexID % 4;
if (vertex_index == 0) {
// "top left" aka "p1"
screen02 += up_dir * pixel - line_dir * pixel;
v_texcoord = a_pos.xy + up_dir * 1.0 / u_scale - line_dir * 1.0 / u_scale;
} else if (vertex_index == 1) {
// "top right" aka "p2"
screen02 += up_dir * pixel + line_dir * pixel;
v_texcoord = a_pos.xy + up_dir * 1.0 / u_scale + line_dir * 1.0 / u_scale;
} else if (vertex_index == 2) {
// "bottom left" aka "p3"
screen02 += -up_dir * pixel - line_dir * pixel;
v_texcoord = a_pos.xy - up_dir * 1.0 / u_scale - line_dir * 1.0 / u_scale;
} else {
// "bottom right" aka "p4"
screen02 += -up_dir * pixel + line_dir * pixel;
v_texcoord = a_pos.xy - up_dir * 1.0 / u_scale + line_dir * 1.0 / u_scale;
}
} else {
// "bottom right" aka "p4"
screen02 += -up_dir * pixel + line_dir * pixel;
v_texcoord = a_pos.xy - up_dir * 1.0 / u_scale + line_dir * 1.0 / u_scale;
v_texcoord = a_pos.xy;
}
screen02.y = 2.0 - screen02.y;
@ -303,6 +308,7 @@ function init_webgl(state, context) { @@ -303,6 +308,7 @@ function init_webgl(state, context) {
'u_debug_mode': gl.getUniformLocation(context.programs['sdf'].main, 'u_debug_mode'),
'u_tile_size': gl.getUniformLocation(context.programs['sdf'].main, 'u_tile_size'),
'u_stroke_count': gl.getUniformLocation(context.programs['sdf'].main, 'u_stroke_count'),
'u_shrink': gl.getUniformLocation(context.programs['sdf'].main, 'u_shrink'),
}
};

2
server/recv.js

@ -52,7 +52,7 @@ async function recv_syn(d, session) { @@ -52,7 +52,7 @@ async function recv_syn(d, session) {
'$id': session.id,
'$lsn': lsn
});
send.send_ack(session.ws, lsn);
send.sync_desk(session.desk_id);
}

2
server/send.js

@ -206,7 +206,7 @@ async function sync_session(session_id) { @@ -206,7 +206,7 @@ async function sync_session(session_id) {
}
let size = 1 + 4 + 4; // opcode + sn + event count
let count = desk.sn - session.sn;
let count = desk.sn - session.sn;
if (count === 0) {
if (config.DEBUG_PRINT) console.log('client ACKed all events');

Loading…
Cancel
Save