diff --git a/README.md b/README.md
index aa8d7b8..c518925 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@ Release:
* Engine
+ Benchmark harness
+ Reuse points, pack "nodraw" in high bit of stroke id (probably have at least one more bit, so up to 4 flag configurations)
- - Draw dynamic data (strokes in progress)
+ + Draw dynamic data (strokes in progress)
- Textured quads (pictures, code already written in older version)
- Resize and move pictures (draw handles)
- Z-prepass fringe bug (also, when do we enable the prepass?)
@@ -26,6 +26,8 @@ Release:
- Polish
- Show what's happening while the desk is loading (downloading, processing, uploading to gpu)
- Settings panel (including the setting for "offline mode")
+ - Use typedvector where appropriate
+ - Set up VAOs
- Presentation / "marketing"
- Title
- Icon
diff --git a/client/aux.js b/client/aux.js
index faa0fa5..2d533fb 100644
--- a/client/aux.js
+++ b/client/aux.js
@@ -33,7 +33,7 @@ async function insert_image(state, context, file) {
}
function event_size(event) {
- let size = 1 + 3; // type + padding
+ let size = 4; // type
switch (event.type) {
case EVENT.PREDRAW: {
diff --git a/client/client_recv.js b/client/client_recv.js
index 97075bc..2a178ae 100644
--- a/client/client_recv.js
+++ b/client/client_recv.js
@@ -87,7 +87,6 @@ function des_event(d, state = null) {
state.coordinates.count += point_count * 2;
event.stroke_id = stroke_id;
- event.lods = [];
event.color = color;
event.width = width;
@@ -304,7 +303,7 @@ function handle_event(state, context, event, options = {}) {
}
async function handle_message(state, context, d) {
- const message_type = des_u8(d);
+ const message_type = des_u32(d);
let do_draw = false;
// if (config.debug_print) console.debug(message_type);
@@ -421,7 +420,7 @@ async function handle_message(state, context, d) {
if (config.debug_print) console.debug(`syn ${sn} in`);
for (let i = 0; i < count; ++i) {
- const event = des_event(d);
+ const event = des_event(d, state);
if (i >= first) {
const need_draw = handle_event(state, context, event);
do_draw = do_draw || need_draw;
diff --git a/client/client_send.js b/client/client_send.js
index e0a9a15..07d33b3 100644
--- a/client/client_send.js
+++ b/client/client_send.js
@@ -43,11 +43,6 @@ function ser_clear(s) {
s.gpu_upload_from = 0;
}
-function ser_u8(s, value) {
- s.view.setUint8(s.offset, value);
- s.offset += 1;
-}
-
function ser_u16(s, value) {
s.view.setUint16(s.offset, value, true);
s.offset += 2;
@@ -71,7 +66,7 @@ function ser_align(s, to) {
}
function ser_event(s, event) {
- ser_u8(s, event.type);
+ ser_u32(s, event.type);
switch (event.type) {
case EVENT.PREDRAW: {
@@ -101,8 +96,6 @@ function ser_event(s, event) {
if (config.debug_print) console.debug('original', event.points);
- ser_align(s, 4);
-
for (const point of event.points) {
ser_f32(s, point.x);
ser_f32(s, point.y);
@@ -137,9 +130,9 @@ function ser_event(s, event) {
}
async function send_ack(sn) {
- const s = serializer_create(1 + 4);
+ const s = serializer_create(4 + 4);
- ser_u8(s, MESSAGE.ACK);
+ ser_u32(s, MESSAGE.ACK);
ser_u32(s, sn);
if (config.debug_print) console.debug(`ack ${sn} out`);
@@ -158,7 +151,7 @@ async function sync_queue(state) {
return;
}
- let size = 1 + 3 + 4 + 4; // opcode + lsn + event count
+ let size = 4 + 4 + 4; // opcode + lsn + event count
let count = state.lsn - state.server_lsn;
if (count === 0) {
@@ -174,7 +167,7 @@ async function sync_queue(state) {
const s = serializer_create(size);
- ser_u8(s, MESSAGE.SYN);
+ ser_u32(s, MESSAGE.SYN);
ser_u32(s, state.lsn);
ser_u32(s, count);
@@ -251,9 +244,9 @@ function queue_event(state, event, skip = false) {
async function fire_event(state, event) {
if (!state.online) { return; }
- const s = serializer_create(1 + event_size(event));
+ const s = serializer_create(4 + event_size(event));
- ser_u8(s, MESSAGE.FIRE);
+ ser_u32(s, MESSAGE.FIRE);
ser_event(s, event);
try {
diff --git a/client/index.js b/client/index.js
index ba26382..22de0e0 100644
--- a/client/index.js
+++ b/client/index.js
@@ -22,7 +22,8 @@ const config = {
bytes_per_stroke: 2 * 3 + 2, // r, g, b, width
initial_static_bytes: 4096 * 16,
initial_dynamic_bytes: 4096,
- stroke_texture_size: 1024,
+ stroke_texture_size: 1024, // means no more than 1024^2 = 1M strokes in total (this is a LOT. HMH blackboard has like 80K)
+ dynamic_stroke_texture_size: 128, // means no more than 128^2 = 16K dynamic strokes at once
benchmark: {
zoom: 0.035,
offset: { x: 900, y: 400 },
@@ -245,10 +246,15 @@ function main() {
'instance_data_points': tv_create(Float32Array, 4096),
'instance_data_ids': tv_create(Uint32Array, 4096),
+
+ 'dynamic_instance_points': tv_create(Float32Array, 4096),
+ 'dynamic_instance_ids': tv_create(Uint32Array, 4096),
- 'lods': [],
-
'stroke_data': serializer_create(config.initial_static_bytes),
+ 'dynamic_stroke_data': serializer_create(config.initial_static_bytes),
+
+ 'dynamic_stroke_count': 0,
+ 'dynamic_segment_count': 0,
'bgcolor': {'r': 1.0, 'g': 1.0, 'b': 1.0},
@@ -261,18 +267,6 @@ function main() {
const url = new URL(window.location.href);
const parts = url.pathname.split('/');
- config.lod_levels = Math.ceil(Math.log2(1.0 / config.min_zoom));
-
- for (let i = 0; i < config.lod_levels; ++i) {
- context.lods.push({
- 'max_zoom': Math.pow(0.25, i), // use this LOD level when current canvas.zoom is less than this value, but not less than the next level max_zoom (or if this is the last zoom level)
- 'total_points': 0,
- 'segments': serializer_create(config.initial_static_bytes),
- 'data_buffer': null,
- 'index_buffer': null,
- });
- }
-
state.desk_id = parts.length > 0 ? parts[parts.length - 1] : 0;
init_webgl(state, context);
diff --git a/client/math.js b/client/math.js
index 8d44689..62fd7b5 100644
--- a/client/math.js
+++ b/client/math.js
@@ -50,6 +50,7 @@ function rdp_find_max(state, zoom, stroke, start, end) {
return result;
}
*/
+
function process_rdp_indices_r(state, zoom, mask, stroke, start, end) {
// Looks like the recursive implementation spends most of its time in the function call overhead
// Let's try to use an explicit stack instead to give the js engine more room to play with
@@ -124,6 +125,72 @@ function process_stroke(state, zoom, stroke) {
return npoints;
}
+function rdp_find_max2(points, start, end) {
+ const EPS = 0.5;
+
+ let result = -1;
+ let max_dist = 0;
+
+ const a = points[start];
+ const b = points[end];
+
+ const dx = b.x - a.x;
+ const dy = b.y - a.y;
+
+ const dist_ab = Math.sqrt(dx * dx + dy * dy);
+ const sin_theta = dy / dist_ab;
+ const cos_theta = dx / dist_ab;
+
+ for (let i = start; i < end; ++i) {
+ const p = points[i];
+
+ const ox = p.x - a.x;
+ const oy = p.y - a.y;
+
+ const rx = cos_theta * ox + sin_theta * oy;
+ const ry = -sin_theta * ox + cos_theta * oy;
+
+ const x = rx + a.x;
+ const y = ry + a.y;
+
+ const dist = Math.abs(y - a.y);
+
+ if (dist > EPS && dist > max_dist) {
+ result = i;
+ max_dist = dist;
+ }
+ }
+
+ return result;
+}
+
+function process_rdp_r2(points, start, end) {
+ let result = [];
+
+ const max = rdp_find_max2(points, start, end);
+
+ if (max !== -1) {
+ const before = process_rdp_r2(points, start, max);
+ const after = process_rdp_r2(points, max, end);
+ result = [...before, points[max], ...after];
+ }
+
+ return result;
+}
+
+function process_rdp2(points) {
+ const result = process_rdp_r2(points, 0, points.length - 1);
+ result.unshift(points[0]);
+ result.push(points[points.length - 1]);
+ return result;
+}
+
+// TODO: unify with regular process stroke
+function process_stroke2(points) {
+ const result = process_rdp2(points);
+ return result;
+}
+
function strokes_intersect_line(state, a, b) {
// TODO: handle stroke / eraser width
const result = [];
diff --git a/client/webgl_draw.js b/client/webgl_draw.js
index 31a8937..80ff898 100644
--- a/client/webgl_draw.js
+++ b/client/webgl_draw.js
@@ -73,11 +73,17 @@ function draw(state, context) {
bvh_clip(state, context);
const segment_count = geometry_write_instances(state, context);
+ const dynamic_segment_count = context.dynamic_segment_count;
+ const dynamic_stroke_count = context.dynamic_stroke_count;
+ // "Static" data upload
gl.bindBuffer(gl.ARRAY_BUFFER, buffers['b_instance']);
gl.bufferData(gl.ARRAY_BUFFER, context.instance_data_points.size * 4 + context.instance_data_ids.size * 4, gl.STREAM_DRAW);
gl.bufferSubData(gl.ARRAY_BUFFER, 0, tv_data(context.instance_data_points));
gl.bufferSubData(gl.ARRAY_BUFFER, context.instance_data_points.size * 4, tv_data(context.instance_data_ids));
+ gl.bindTexture(gl.TEXTURE_2D, context.textures['stroke_data']);
+ // TODO: this is stable data, only upload new strokes as they arrive
+ upload_square_rgba16ui_texture(gl, context.stroke_data, config.stroke_texture_size);
gl.uniform2f(locations['u_res'], context.canvas.width, context.canvas.height);
gl.uniform2f(locations['u_scale'], state.canvas.zoom, state.canvas.zoom);
@@ -91,7 +97,7 @@ function draw(state, context) {
gl.enableVertexAttribArray(locations['a_b']);
gl.enableVertexAttribArray(locations['a_stroke_id']);
- // Points (a, b) and stroke ids are not stored in separate cpu buffers so that points can be resued
+ // Points (a, b) and stroke ids are stored in separate cpu buffers so that points can be reused (look at stride and offset values)
gl.vertexAttribPointer(locations['a_a'], 2, gl.FLOAT, false, 2 * 4, 0);
gl.vertexAttribPointer(locations['a_b'], 2, gl.FLOAT, false, 2 * 4, 2 * 4);
gl.vertexAttribIPointer(locations['a_stroke_id'], 1, gl.INT, 4, context.instance_data_points.size * 4);
@@ -99,81 +105,47 @@ function draw(state, context) {
gl.vertexAttribDivisor(locations['a_a'], 1);
gl.vertexAttribDivisor(locations['a_b'], 1);
gl.vertexAttribDivisor(locations['a_stroke_id'], 1);
-
- gl.bindTexture(gl.TEXTURE_2D, context.textures['stroke_data']);
- // TODO: this is stable data, only upload new strokes as they arrive
- upload_square_rgba16ui_texture(gl, context.stroke_data, config.stroke_texture_size);
- gl.activeTexture(gl.TEXTURE0);
-
- gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, segment_count); // TODO: based on clipping results
- document.getElementById('debug-stats').innerHTML = `
- Segments onscreen: ${segment_count}
- Canvas offset: (${state.canvas.offset.x}, ${state.canvas.offset.y})
- Canvas zoom: ${Math.round(state.canvas.zoom * 100000) / 100000}`;
-
- /*
- // 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.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.clear(gl.DEPTH_BUFFER_BIT);
-
- gl.bindBuffer(gl.ARRAY_BUFFER, buffers['b_packed_dynamic']);
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers['b_packed_dynamic_index']);
-
- gl.enableVertexAttribArray(locations['a_pos']);
- gl.enableVertexAttribArray(locations['a_line']);
- gl.enableVertexAttribArray(locations['a_color']);
- gl.enableVertexAttribArray(locations['a_stroke_id']);
+ // Static draw (everything already bound)
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, segment_count);
+
+ // Dynamic strokes should be drawn above static strokes
+ gl.clear(gl.DEPTH_BUFFER_BIT);
- 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);
+ // Dynamic draw (strokes currently being drawn)
+ gl.uniform1i(locations['u_stroke_count'], dynamic_stroke_count);
+ gl.uniform1i(locations['u_stroke_data'], 0);
+ gl.uniform1i(locations['u_stroke_texture_size'], config.dynamic_stroke_texture_size);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffers['b_dynamic_instance']);
- const dynamic_indices = [];
- let base = 0;
+ // Dynamic data upload
+ gl.bufferData(gl.ARRAY_BUFFER, context.dynamic_instance_points.size * 4 + context.dynamic_instance_ids.size * 4, gl.STREAM_DRAW);
+ gl.bufferSubData(gl.ARRAY_BUFFER, 0, tv_data(context.dynamic_instance_points));
+ gl.bufferSubData(gl.ARRAY_BUFFER, context.dynamic_instance_points.size * 4, tv_data(context.dynamic_instance_ids));
+ gl.bindTexture(gl.TEXTURE_2D, context.textures['dynamic_stroke_data']);
+ upload_square_rgba16ui_texture(gl, context.dynamic_stroke_data, config.dynamic_stroke_texture_size);
- 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 > 1) {
- for (let i = 0; i < player.points.length - 1; ++i) {
- dynamic_indices.push(base + 0);
- dynamic_indices.push(base + 1);
- dynamic_indices.push(base + 2);
- dynamic_indices.push(base + 3);
- dynamic_indices.push(base + 2);
- dynamic_indices.push(base + 1);
+ gl.enableVertexAttribArray(locations['a_a']);
+ gl.enableVertexAttribArray(locations['a_b']);
+ gl.enableVertexAttribArray(locations['a_stroke_id']);
+
+ // Points (a, b) and stroke ids are stored in separate cpu buffers so that points can be reused (look at stride and offset values)
+ gl.vertexAttribPointer(locations['a_a'], 2, gl.FLOAT, false, 2 * 4, 0);
+ gl.vertexAttribPointer(locations['a_b'], 2, gl.FLOAT, false, 2 * 4, 2 * 4);
+ gl.vertexAttribIPointer(locations['a_stroke_id'], 1, gl.INT, 4, context.dynamic_instance_points.size * 4);
- base += 4;
- }
- }
- }
+ gl.vertexAttribDivisor(locations['a_a'], 1);
+ gl.vertexAttribDivisor(locations['a_b'], 1);
+ gl.vertexAttribDivisor(locations['a_stroke_id'], 1);
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, dynamic_segment_count);
- if (context.need_dynamic_upload) {
- gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(context.dynamic_serializer.buffer, 0, context.dynamic_serializer.offset), gl.DYNAMIC_DRAW);
- gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(dynamic_indices), gl.DYNAMIC_DRAW);
- context.need_dynamic_upload = false;
- }
+ document.getElementById('debug-stats').innerHTML = `
+ Segments onscreen: ${segment_count}
+ Canvas offset: (${state.canvas.offset.x}, ${state.canvas.offset.y})
+ Canvas zoom: ${Math.round(state.canvas.zoom * 100000) / 100000}`;
- gl.drawElements(gl.TRIANGLES, dynamic_indices.length, gl.UNSIGNED_INT, 0);
- }
-*/
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 20c2dd6..20649cc 100644
--- a/client/webgl_geometry.js
+++ b/client/webgl_geometry.js
@@ -24,9 +24,9 @@ function geometry_prepare_stroke(state) {
if (state.players[state.me].points.length === 0) {
return null;
- }
+ }
- const points = process_stroke(state, state.canvas.zoom, state.players[state.me].points);
+ const points = process_stroke2(state.players[state.me].points);
return {
'color': state.players[state.me].color,
@@ -223,30 +223,62 @@ function geometry_delete_stroke(state, context, stroke_index) {
}
function recompute_dynamic_data(state, context) {
- let bytes_needed = 0;
+ let total_points = 0;
+ let total_strokes = 0;
for (const player_id in state.players) {
const player = state.players[player_id];
if (player.points.length > 0) {
- bytes_needed += player.points.length * 6 * config.bytes_per_point;
+ total_points += player.points.length;
+ total_strokes += 1;
}
}
- if (bytes_needed > context.dynamic_serializer.size) {
- context.dynamic_serializer = serializer_create(Math.ceil(bytes_needed * 1.62));
- } else {
- context.dynamic_serializer.offset = 0;
- }
+ context.dynamic_instance_data = tv_ensure(context.dynamic_instance_points, round_to_pow2(total_points * 2, 4096));
+ context.dynamic_instance_ids = tv_ensure(context.dynamic_instance_ids, round_to_pow2(total_points, 4096));
+
+ tv_clear(context.dynamic_instance_points);
+ tv_clear(context.dynamic_instance_ids);
+
+ context.dynamic_stroke_data = ser_ensure(context.dynamic_stroke_data, config.bytes_per_stroke * total_strokes);
+ ser_clear(context.dynamic_stroke_data);
+
+ let stroke_index = 0;
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 > 1) {
- push_stroke(context.dynamic_serializer, player, 0);
+
+ for (let i = 0; i < player.points.length; ++i) {
+ const p = player.points[i];
+
+ tv_add(context.dynamic_instance_points, p.x);
+ tv_add(context.dynamic_instance_points, p.y);
+
+ if (i !== player.points.length - 1) {
+ tv_add(context.dynamic_instance_ids, stroke_index);
+ } else {
+ tv_add(context.dynamic_instance_ids, stroke_index | (1 << 31));
+ }
+ }
+
+ if (player.points.length > 0) {
+ const color_u32 = player.color;
+ const r = (color_u32 >> 16) & 0xFF;
+ const g = (color_u32 >> 8) & 0xFF;
+ const b = color_u32 & 0xFF;
+
+ ser_u16(context.dynamic_stroke_data, r);
+ ser_u16(context.dynamic_stroke_data, g);
+ ser_u16(context.dynamic_stroke_data, b);
+ ser_u16(context.dynamic_stroke_data, player.width);
+
+ stroke_index += 1; // TODO: proper player Z order
}
}
- context.need_dynamic_upload = true;
+ context.dynamic_segment_count = total_points;
+ context.dynamic_stroke_count = total_strokes;
}
function geometry_add_point(state, context, player_id, point) {
diff --git a/client/webgl_listeners.js b/client/webgl_listeners.js
index 3cc8cad..50bfe89 100644
--- a/client/webgl_listeners.js
+++ b/client/webgl_listeners.js
@@ -279,9 +279,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);
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 1520e9e..c03f614 100644
--- a/client/webgl_shaders.js
+++ b/client/webgl_shaders.js
@@ -323,24 +323,18 @@ function init_webgl(state, context) {
}
};
- for (let i = 0; i < context.lods.length; ++i) {
- const level = context.lods[i];
- level.data_buffer = gl.createBuffer();
- level.index_buffer = gl.createBuffer();
- }
-
context.buffers['debug'] = {
'b_packed': gl.createBuffer(),
};
context.buffers['sdf'] = {
- 'b_packed_dynamic': gl.createBuffer(),
- 'b_packed_dynamic_index': gl.createBuffer(),
'b_instance': gl.createBuffer(),
+ 'b_dynamic_instance': gl.createBuffer(),
};
context.textures = {
'stroke_data': gl.createTexture(),
+ 'dynamic_stroke_data': gl.createTexture(),
};
gl.bindTexture(gl.TEXTURE_2D, context.textures['stroke_data']);
@@ -348,6 +342,11 @@ function init_webgl(state, context) {
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16UI, config.stroke_texture_size, config.stroke_texture_size, 0, gl.RGBA_INTEGER, gl.UNSIGNED_SHORT, null);
+ gl.bindTexture(gl.TEXTURE_2D, context.textures['dynamic_stroke_data']);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16UI, config.dynamic_stroke_texture_size, config.dynamic_stroke_texture_size, 0, gl.RGBA_INTEGER, gl.UNSIGNED_SHORT, null);
+
const resize_canvas = (entries) => {
// https://www.khronos.org/webgl/wiki/HandlingHighDPI
const entry = entries[0];
diff --git a/server/deserializer.js b/server/deserializer.js
index feafca4..c404971 100644
--- a/server/deserializer.js
+++ b/server/deserializer.js
@@ -47,7 +47,7 @@ export function align(d, to) {
export function event(d) {
const event = {};
- event.type = u8(d);
+ event.type = u32(d);
switch (event.type) {
case EVENT.PREDRAW: {
@@ -75,7 +75,6 @@ export function event(d) {
const point_count = u16(d);
const width = u16(d);
const color = u32(d);
- align(d, 4);
event.width = width;
event.color = color;
event.points = f32array(d, point_count * 2);
@@ -108,4 +107,4 @@ export function event(d) {
}
return event;
-}
\ No newline at end of file
+}
diff --git a/server/recv.js b/server/recv.js
index 9dd29b0..2281fde 100644
--- a/server/recv.js
+++ b/server/recv.js
@@ -164,7 +164,7 @@ export async function handle_message(ws, d) {
const session = sessions[ws.data.session_id];
const desk_id = session.desk_id;
- const message_type = des.u8(d);
+ const message_type = des.u32(d);
switch (message_type) {
case MESSAGE.FIRE: {
diff --git a/server/send.js b/server/send.js
index b040c26..1ff6157 100644
--- a/server/send.js
+++ b/server/send.js
@@ -94,7 +94,7 @@ export async function send_init(ws) {
const desk = desks[desk_id];
let opcode = MESSAGE.INIT;
- let size = 1 + 4 + 4 + 4 + 4 + 4 + 3; // opcode + user_id + lsn + event count + stroke count + user count + total_point_count + align on 4
+ let size = 4 + 4 + 4 + 4 + 4 + 4; // opcode + user_id + lsn + event count + stroke count + user count + total_point_count
let session = null;
if (session_id in sessions && sessions[session_id].desk_id == desk_id) {
@@ -130,7 +130,7 @@ export async function send_init(ws) {
const s = ser.create(size);
- ser.u8(s, opcode);
+ ser.u32(s, opcode);
ser.u32(s, session.lsn);
if (opcode === MESSAGE.JOIN) {
@@ -168,10 +168,10 @@ export function send_ack(ws, lsn) {
return;
}
- const size = 1 + 4; // opcode + lsn
+ const size = 4 + 4; // opcode + lsn
const s = ser.create(size);
- ser.u8(s, MESSAGE.ACK);
+ ser.u32(s, MESSAGE.ACK);
ser.u32(s, lsn);
if (config.DEBUG_PRINT) console.log(`ack ${lsn} out`);
@@ -184,9 +184,9 @@ export function send_fire(ws, event) {
return;
}
- const s = ser.create(1 + 4 + event_size(event));
+ const s = ser.create(4 + 4 + event_size(event));
- ser.u8(s, MESSAGE.FIRE);
+ ser.u32(s, MESSAGE.FIRE);
ser.event(s, event);
ws.send(s.buffer);
@@ -208,7 +208,7 @@ async function sync_session(session_id) {
return;
}
- let size = 1 + 4 + 4; // opcode + sn + event count
+ let size = 4 + 4 + 4; // opcode + sn + event count
let count = desk.sn - session.sn;
if (count === 0) {
@@ -223,7 +223,7 @@ async function sync_session(session_id) {
const s = ser.create(size);
- ser.u8(s, MESSAGE.SYN);
+ ser.u32(s, MESSAGE.SYN);
ser.u32(s, desk.sn);
ser.u32(s, count);