diff --git a/client/bvh.js b/client/bvh.js
index c913a6f..c499c55 100644
--- a/client/bvh.js
+++ b/client/bvh.js
@@ -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) {
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) {
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) {
}
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;
diff --git a/client/client_recv.js b/client/client_recv.js
index 6df8d55..f82d77a 100644
--- a/client/client_recv.js
+++ b/client/client_recv.js
@@ -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 = {}) {
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) {
}
}
+ state.sn = event_count;
+
bvh_construct(state);
document.getElementById('debug-render-from').max = state.stroke_count;
diff --git a/client/index.html b/client/index.html
index 97c8c3f..f1c1760 100644
--- a/client/index.html
+++ b/client/index.html
@@ -41,7 +41,6 @@
-
diff --git a/client/index.js b/client/index.js
index 317936b..5fb5ae2 100644
--- a/client/index.js
+++ b/client/index.js
@@ -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() {
'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() {
},
'players': {},
- 'onscreen_segments': null,
+ 'onscreen_segments': new Uint32Array(1024),
'debug': {
'red': false,
@@ -198,7 +200,6 @@ function main() {
'limit_to': false,
'render_from': 0,
'render_to': 0,
- 'force_clip_off': false,
'draw_bvh': false,
}
};
diff --git a/client/webgl_draw.js b/client/webgl_draw.js
index 56183ce..5e3979c 100644
--- a/client/webgl_draw.js
+++ b/client/webgl_draw.js
@@ -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) {
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) {
}
}
+ // 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) {
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);
diff --git a/client/webgl_geometry.js b/client/webgl_geometry.js
index 33fd2dc..4b56b39 100644
--- a/client/webgl_geometry.js
+++ b/client/webgl_geometry.js
@@ -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) {
to.x, to.y,
stroke_width,
r, g, b,
- stroke_index
+ stroke_index,
+ indexed
);
}
}
@@ -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) {
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);
}
}
diff --git a/client/webgl_listeners.js b/client/webgl_listeners.js
index 3d23714..387fe59 100644
--- a/client/webgl_listeners.js
+++ b/client/webgl_listeners.js
@@ -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) {
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) {
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);
}
diff --git a/client/webgl_shaders.js b/client/webgl_shaders.js
index 8790c39..d615e36 100644
--- a/client/webgl_shaders.js
+++ b/client/webgl_shaders.js
@@ -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
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) {
'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'),
}
};
diff --git a/server/recv.js b/server/recv.js
index d33ea1e..82b2932 100644
--- a/server/recv.js
+++ b/server/recv.js
@@ -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);
}
diff --git a/server/send.js b/server/send.js
index 829a600..80907b5 100644
--- a/server/send.js
+++ b/server/send.js
@@ -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');