|
|
|
@ -23,7 +23,23 @@ function push_quad_xyzrgb(s, p1x, p1y, p4x, p4y, z, r, g, b) {
@@ -23,7 +23,23 @@ function push_quad_xyzrgb(s, p1x, p1y, p4x, p4y, z, r, g, b) {
|
|
|
|
|
push_point_xyzrgb(s, p4x, p1y, z, r, g, b); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const MAX_POINTS_PER_QUAD = 10; |
|
|
|
|
const MAX_QUAD_SIDE = 256; |
|
|
|
|
|
|
|
|
|
function count_stroke_quads(points) { |
|
|
|
|
let min_x, min_y, max_x, max_y; |
|
|
|
|
let points_per_quad = 0; |
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
|
|
return Math.ceil(points.length / MAX_POINTS_PER_QUAD); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function push_stroke(context, stroke) { |
|
|
|
|
// if (stroke.stroke_id !== 1123776468) {
|
|
|
|
|
// return;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
const stroke_width = stroke.width; |
|
|
|
|
const points = stroke.points; |
|
|
|
|
const color_u32 = stroke.color; |
|
|
|
@ -36,11 +52,8 @@ function push_stroke(context, stroke) {
@@ -36,11 +52,8 @@ function push_stroke(context, stroke) {
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const points_from = context.point_serializer.offset / (4 * 2); // 4 is sizeof(f32) btw, just sain'
|
|
|
|
|
const points_to = points_from + points.length; |
|
|
|
|
|
|
|
|
|
ser_u32(context.index_serializer, points_from); |
|
|
|
|
ser_u32(context.index_serializer, points_to); |
|
|
|
|
let points_from = context.point_serializer.offset / (4 * 2); // 4 is sizeof(f32) btw, just sain'
|
|
|
|
|
const points_start = points_from; |
|
|
|
|
|
|
|
|
|
let min_x, min_y, max_x, max_y; |
|
|
|
|
|
|
|
|
@ -50,15 +63,58 @@ function push_stroke(context, stroke) {
@@ -50,15 +63,58 @@ function push_stroke(context, stroke) {
|
|
|
|
|
min_y = Math.floor(points[0].y - stroke_width / 2); |
|
|
|
|
max_y = Math.ceil(points[0].y + stroke_width / 2); |
|
|
|
|
|
|
|
|
|
for (const p of points) { |
|
|
|
|
let points_per_quad = 0; |
|
|
|
|
|
|
|
|
|
for (let i = 0; i < points.length; ++i) { |
|
|
|
|
const p = points[i]; |
|
|
|
|
|
|
|
|
|
min_x = Math.min(min_x, Math.floor(p.x - stroke_width / 2)); |
|
|
|
|
min_y = Math.min(min_y, Math.floor(p.y - stroke_width / 2)); |
|
|
|
|
max_x = Math.max(max_x, Math.ceil(p.x + stroke_width / 2)); |
|
|
|
|
max_y = Math.max(max_y, Math.ceil(p.y + stroke_width / 2)); |
|
|
|
|
|
|
|
|
|
push_point_xy(context.point_serializer, p.x, p.y); |
|
|
|
|
|
|
|
|
|
points_per_quad++; |
|
|
|
|
|
|
|
|
|
if (points_per_quad == MAX_POINTS_PER_QUAD) { |
|
|
|
|
let points_to = points_from + MAX_POINTS_PER_QUAD; |
|
|
|
|
|
|
|
|
|
if (points_from > points_start) { |
|
|
|
|
// 1 point overlap to prevent gaps
|
|
|
|
|
ser_u32(context.index_serializer, points_from - 1); |
|
|
|
|
} else { |
|
|
|
|
ser_u32(context.index_serializer, points_from); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ser_u32(context.index_serializer, points_to); |
|
|
|
|
|
|
|
|
|
push_quad_xyzrgb(context.quad_serializer, min_x, min_y, max_x, max_y, stroke_width / 2, r, g, b); |
|
|
|
|
|
|
|
|
|
min_x = Math.floor(p.x - stroke_width / 2); |
|
|
|
|
max_x = Math.ceil(p.x + stroke_width / 2); |
|
|
|
|
|
|
|
|
|
min_y = Math.floor(p.y - stroke_width / 2); |
|
|
|
|
max_y = Math.ceil(p.y + stroke_width / 2); |
|
|
|
|
|
|
|
|
|
points_from = points_to; |
|
|
|
|
points_per_quad = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
push_quad_xyzrgb(context.quad_serializer, min_x, min_y, max_x, max_y, stroke_width / 2, r, g, b); |
|
|
|
|
if (points_per_quad > 0) { |
|
|
|
|
const points_to = points_from + points_per_quad; |
|
|
|
|
|
|
|
|
|
if (points_from > points_start) { |
|
|
|
|
ser_u32(context.index_serializer, points_from - 1); |
|
|
|
|
} else { |
|
|
|
|
ser_u32(context.index_serializer, points_from); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ser_u32(context.index_serializer, points_to); |
|
|
|
|
|
|
|
|
|
push_quad_xyzrgb(context.quad_serializer, min_x, min_y, max_x, max_y, stroke_width / 2, r, g, b); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function geometry_prepare_stroke(state) { |
|
|
|
@ -76,17 +132,35 @@ function geometry_prepare_stroke(state) {
@@ -76,17 +132,35 @@ function geometry_prepare_stroke(state) {
|
|
|
|
|
|
|
|
|
|
function geometry_add_stroke(state, context, stroke) { |
|
|
|
|
if (!state.online || !stroke) return; |
|
|
|
|
if (stroke.points.length < 2) return; |
|
|
|
|
|
|
|
|
|
const bytes_left = context.point_serializer.size - context.point_serializer.offset; |
|
|
|
|
const bytes_needed = stroke.points.length * config.bytes_per_point; |
|
|
|
|
const stroke_quads = count_stroke_quads(stroke.points); |
|
|
|
|
// const stroke_quads = Math.ceil(stroke.points.length / MAX_POINTS_PER_QUAD);
|
|
|
|
|
|
|
|
|
|
if (bytes_left < bytes_needed) { |
|
|
|
|
const extend_points_by = Math.ceil((context.point_serializer.size + bytes_needed) * 1.62); |
|
|
|
|
const extend_indices_by = Math.ceil((context.index_serializer.size + stroke.points.length * 4 * 2) * 1.62); |
|
|
|
|
const extend_quads_by = Math.ceil((context.quad_serializer.size + 6 * (4 * 3)) * 1.62); |
|
|
|
|
// Points
|
|
|
|
|
const point_bytes_left = context.point_serializer.size - context.point_serializer.offset; |
|
|
|
|
const point_bytes_needed = stroke.points.length * config.bytes_per_point; |
|
|
|
|
|
|
|
|
|
if (point_bytes_left < point_bytes_needed) { |
|
|
|
|
const extend_points_by = Math.ceil((context.point_serializer.size + point_bytes_needed) * 1.62); |
|
|
|
|
context.point_serializer = ser_extend(context.point_serializer, extend_points_by); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Indices
|
|
|
|
|
const index_bytes_left = context.index_serializer.size - context.index_serializer.offset; |
|
|
|
|
const index_bytes_needed = stroke_quads * (4 * 2); |
|
|
|
|
|
|
|
|
|
if (index_bytes_left < index_bytes_needed) { |
|
|
|
|
const extend_indices_by = Math.ceil((context.index_serializer.size + index_bytes_needed) * 1.62); |
|
|
|
|
context.index_serializer = ser_extend(context.index_serializer, extend_indices_by); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Quads
|
|
|
|
|
const quad_bytes_left = context.quad_serializer.size - context.quad_serializer.offset; |
|
|
|
|
const quad_bytes_needed = stroke_quads * 6 * (4 * 4); |
|
|
|
|
|
|
|
|
|
if (quad_bytes_left < quad_bytes_needed) { |
|
|
|
|
const extend_quads_by = Math.ceil((context.quad_serializer.size + quad_bytes_needed) * 1.62); |
|
|
|
|
context.quad_serializer = ser_extend(context.quad_serializer, extend_quads_by); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -151,6 +225,8 @@ function geometry_clear_player(state, context, player_id) {
@@ -151,6 +225,8 @@ function geometry_clear_player(state, context, player_id) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function add_image(context, image_id, bitmap, p) { |
|
|
|
|
return; // TODO
|
|
|
|
|
|
|
|
|
|
const x = p.x; |
|
|
|
|
const y = p.y; |
|
|
|
|
const gl = context.gl; |
|
|
|
@ -161,7 +237,7 @@ function add_image(context, image_id, bitmap, p) {
@@ -161,7 +237,7 @@ function add_image(context, image_id, bitmap, p) {
|
|
|
|
|
'image_id': image_id |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
gl.bindTexture(gl.TEXTURE_2D, context.textures[id].texture); |
|
|
|
|
gl.bindTexture(gl.TEXTURE_2D, context.textures['image'][id].texture); |
|
|
|
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bitmap); |
|
|
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); |
|
|
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); |
|
|
|
|