Browse Source

I don't even know anymore (colors?)

infinite
A.Olokhtonov 2 years ago
parent
commit
59cb197e58
  1. 22
      client/client_recv.js
  2. 2
      client/client_send.js
  3. 144
      client/default.css
  4. 119
      client/index.html
  5. 6
      client/math.js
  6. 43
      client/tools.js
  7. 8
      client/webgl.js
  8. 22
      client/webgl_geometry.js
  9. 5
      client/webgl_listeners.js

22
client/client_recv.js

@ -116,13 +116,16 @@ function bitmap_bbox(event) { @@ -116,13 +116,16 @@ function bitmap_bbox(event) {
return bbox;
}
async function handle_event(state, context, event, relax = false) {
function handle_event(state, context, event, relax = false) {
if (config.debug_print) console.debug(`event type ${event.type} from user ${event.user_id}`);
let need_draw = false;
switch (event.type) {
case EVENT.STROKE: {
if (event.user_id != state.me) {
clear_dynamic_stroke(state, context, event.user_id);
need_draw = true;
}
add_static_stroke(state, context, event, relax);
@ -131,6 +134,7 @@ async function handle_event(state, context, event, relax = false) { @@ -131,6 +134,7 @@ async function handle_event(state, context, event, relax = false) {
}
case EVENT.UNDO: {
need_draw = true;
console.error('todo');
// for (let i = state.events.length - 1; i >=0; --i) {
// const other_event = state.events[i];
@ -173,6 +177,7 @@ async function handle_event(state, context, event, relax = false) { @@ -173,6 +177,7 @@ async function handle_event(state, context, event, relax = false) {
}
case EVENT.IMAGE: {
need_draw = true;
console.error('todo');
// const url = config.image_url + event.image_id;
// const item = document.createElement('img');
@ -198,6 +203,7 @@ async function handle_event(state, context, event, relax = false) { @@ -198,6 +203,7 @@ async function handle_event(state, context, event, relax = false) {
}
case EVENT.IMAGE_MOVE: {
need_draw = true;
console.error('todo');
// // Already moved due to local prediction
// if (event.user_id !== state.me.id) {
@ -216,6 +222,7 @@ async function handle_event(state, context, event, relax = false) { @@ -216,6 +222,7 @@ async function handle_event(state, context, event, relax = false) {
}
case EVENT.ERASER: {
need_draw = true;
console.error('todo');
// if (event.deleted) {
// break;
@ -239,6 +246,8 @@ async function handle_event(state, context, event, relax = false) { @@ -239,6 +246,8 @@ async function handle_event(state, context, event, relax = false) {
console.error('fuck');
}
}
return need_draw;
}
async function handle_message(state, context, d) {
@ -273,14 +282,14 @@ async function handle_message(state, context, d) { @@ -273,14 +282,14 @@ async function handle_message(state, context, d) {
for (let i = 0; i < event_count; ++i) {
const event = des_event(d);
await handle_event(state, context, event, true);
handle_event(state, context, event, true);
state.events.push(event);
}
recompute_static_data(context);
do_draw = true;
recompute_static_data(context);
send_ack(event_count);
sync_queue(state);
@ -324,13 +333,12 @@ async function handle_message(state, context, d) { @@ -324,13 +333,12 @@ async function handle_message(state, context, d) {
for (let i = 0; i < count; ++i) {
const event = des_event(d);
if (i >= first) {
handle_event(state, context, event);
const need_draw = handle_event(state, context, event);
do_draw = do_draw || need_draw;
state.events.push(event);
}
}
do_draw = true;
state.sn = sn;
send_ack(sn); // await?

2
client/client_send.js

@ -220,7 +220,7 @@ function predraw_event(x, y) { @@ -220,7 +220,7 @@ function predraw_event(x, y) {
function stroke_event(state) {
return {
'type': EVENT.STROKE,
'points': state.current_strokes[state.me].points,
'points': process_stroke(state.current_strokes[state.me].points),
'width': state.current_strokes[state.me].width,
'color': state.current_strokes[state.me].color,
};

144
client/default.css

@ -1,60 +1,38 @@ @@ -1,60 +1,38 @@
:root {
--dark-blue: #2f343d;
--dark-hover: #888;
--radius: 5px;
--hgap: 5px;
--gap: 10px;
}
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
touch-action: none;
}
.dhide {
display: none !important;
}
.canvas {
position: absolute;
top: 0;
left: 0;
opacity: 1;
transition: opacity .2s;
transform-origin: top left;
pointer-events: none;
}
#toucher {
position: fixed;
canvas {
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 5; /* above all canvases, but below tools */
display: block;
cursor: crosshair;
}
.canvas.white {
opacity: 0;
}
#canvas-images {
z-index: 0;
}
#canvas0 {
z-index: 1;
background: #eee;
background-position: 0px 0px;
background-size: 32px 32px;
background-image: radial-gradient(rgba(0, 0, 0, 0.1) 1px, transparent 10%);
canvas.movemode {
cursor: grab;
}
#canvas1 {
z-index: 2;
opacity: 0.3;
canvas.movemode.moving {
cursor: grabbing;
}
.tools-wrapper {
position: fixed;
bottom: 0;
width: 100%;
height: 32px;
display: flex;
justify-content: center;
align-items: end;
@ -62,61 +40,97 @@ html, body { @@ -62,61 +40,97 @@ html, body {
pointer-events: none;
}
.pallete-wrapper {
position: fixed;
top: 0;
left: 0;
height: 100%;
pointer-events: none;
display: flex;
flex-direction: column;
justify-content: center;
}
.pallete {
pointer-events: all;
display: grid;
flex-direction: column;
align-items: center;
background: var(--dark-blue);
border-top-right-radius: var(--radius);
border-bottom-right-radius: var(--radius);
/* border-bottom-left-radius: var(--radius);*/
padding-top: var(--gap);
padding-bottom: var(--gap);
}
.pallete .color {
padding: var(--gap);
cursor: pointer;
background: var(--dark-blue);
transition: transform .1s ease-in-out;
}
.pallete .color:hover {
background: var(--dark-hover);
}
.pallete .color.active {
transform: translateX(10px);
border-top-right-radius: var(--radius);
border-bottom-right-radius: var(--radius);
}
.pallete .color.active:hover {
background: var(--dark-blue);
}
.pallete .color-pane {
width: 24px;
height: 24px;
box-sizing: border-box;
border-radius: var(--radius);
}
.tools {
pointer-events: all;
display: flex;
align-items: center;
justify-content: center;
background: #333;
border-radius: 5px;
background: var(--dark-blue);
border-radius: var(--radius);
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
height: 42px;
padding-left: 10px;
padding-right: 10px;
padding-left: var(--gap);
padding-right: var(--gap);
}
.tool {
cursor: pointer;
padding-left: 10px;
padding-right: 10px;
padding-left: var(--gap);
padding-right: var(--gap);
height: 100%;
display: flex;
align-items: center;
background: #333;
background: var(--dark-blue);
transition: transform .1s ease-in-out;
user-select: none;
}
.tool:hover {
background: #888;
background: var(--dark-hover);
}
.tool.active {
transform: translateY(-10px);
border-top-right-radius: 5px;
border-top-left-radius: 5px;
background: #333;
border-top-right-radius: var(--radius);
border-top-left-radius: var(--radius);
background: var(--dark-blue);
}
.tool img {
height: 24px;
width: 24px;
filter: invert(100%);
}
.toolbar {
visibility: hidden;
}
.floating-image {
position: absolute;
user-drag: none;
user-select: none;
}
.floating-image.activated {
outline: 5px solid #5286ff;
z-index: 999999 !important;
cursor: grab;
}

119
client/index.html

@ -4,106 +4,41 @@ @@ -4,106 +4,41 @@
<meta charset="utf-8">
<title>Desk</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="shortcut icon" href="icons/favicon.svg" id="favicon">
<script type="text/javascript" src="math.js?v=5"></script>
<script type="text/javascript" src="aux.js?v=5"></script>
<script type="text/javascript" src="tools.js?v=5"></script>
<script type="text/javascript" src="webgl_geometry.js?v=5"></script>
<script type="text/javascript" src="webgl_shaders.js?v=5"></script>
<script type="text/javascript" src="webgl_listeners.js?v=5"></script>
<script type="text/javascript" src="webgl.js?v=5"></script>
<script type="text/javascript" src="client_send.js?v=6"></script>
<script type="text/javascript" src="client_recv.js?v=6"></script>
<link rel="shortcut icon" href="icons/favicon.svg" id="favicon">
<link rel="stylesheet" type="text/css" href="default.css?v=7">
<script type="text/javascript" src="math.js?v=6"></script>
<script type="text/javascript" src="aux.js?v=6"></script>
<script type="text/javascript" src="tools.js?v=6"></script>
<script type="text/javascript" src="webgl_geometry.js?v=6"></script>
<script type="text/javascript" src="webgl_shaders.js?v=6"></script>
<script type="text/javascript" src="webgl_listeners.js?v=6"></script>
<script type="text/javascript" src="webgl.js?v=6"></script>
<script type="text/javascript" src="client_send.js?v=7"></script>
<script type="text/javascript" src="client_recv.js?v=7"></script>
<script type="text/javascript" src="websocket.js?v=7"></script>
<style>
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
display: block;
cursor: crosshair;
}
canvas.movemode {
cursor: grab;
}
canvas.movemode.moving {
cursor: grabbing;
}
.tools-wrapper {
position: fixed;
bottom: 0;
width: 100%;
height: 32px;
display: flex;
justify-content: center;
align-items: end;
z-index: 10;
pointer-events: none;
}
.tools {
pointer-events: all;
display: flex;
align-items: center;
justify-content: center;
background: #333;
border-radius: 5px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
height: 42px;
padding-left: 10px;
padding-right: 10px;
}
.tool {
cursor: pointer;
padding-left: 10px;
padding-right: 10px;
height: 100%;
display: flex;
align-items: center;
background: #333;
transition: transform .1s ease-in-out;
user-select: none;
}
.tool:hover {
background: #888;
}
.tool.active {
transform: translateY(-10px);
border-top-right-radius: 5px;
border-top-left-radius: 5px;
background: #333;
}
.tool img {
height: 24px;
width: 24px;
filter: invert(100%);
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<div class="pallete-wrapper">
<div class="pallete">
<div class="color active" data-color="000000"><div class="color-pane" style="background: #000000;"></div></div>
<div class="color" data-color="ffffff" ><div class="color-pane" style="background: #ffffff;"></div></div>
<div class="color" data-color="d65c5c" ><div class="color-pane" style="background: #d65c5c;"></div></div>
<div class="color" data-color="d6835c" ><div class="color-pane" style="background: #d6835c;"></div></div>
<div class="color" data-color="72d65c" ><div class="color-pane" style="background: #72d65c;"></div></div>
<div class="color" data-color="5cd6ce" ><div class="color-pane" style="background: #5cd6ce;"></div></div>
<div class="color" data-color="5c89d6" ><div class="color-pane" style="background: #5c89d6;"></div></div>
<div class="color" data-color="6e5cd6" ><div class="color-pane" style="background: #6e5cd6;"></div></div>
</div>
</div>
<div class="tools-wrapper">
<div class="tools">
<div class="tool" data-tool="pencil"><img draggable="false" src="icons/draw.svg"></div>
<div class="tool active" data-tool="pencil"><img draggable="false" src="icons/draw.svg"></div>
<div class="tool" data-tool="ruler"><img draggable="false" src="icons/ruler.svg"></div>
<div class="tool" data-tool="eraser"><img draggable="false" src="icons/erase.svg"></div>
<div class="tool" data-tool="undo"><img draggable="false" src="icons/undo.svg"></div>

6
client/math.js

@ -166,9 +166,9 @@ function stroke_intersects_region(points, bbox) { @@ -166,9 +166,9 @@ function stroke_intersects_region(points, bbox) {
}
function color_to_u32(color_str) {
const r = parseInt(color_str.substring(1, 3), 16);
const g = parseInt(color_str.substring(3, 5), 16);
const b = parseInt(color_str.substring(5, 7), 16);
const r = parseInt(color_str.substring(0, 2), 16);
const g = parseInt(color_str.substring(2, 4), 16);
const b = parseInt(color_str.substring(4, 6), 16);
return (r << 16) | (g << 8) | b;
}

43
client/tools.js

@ -1,26 +1,35 @@ @@ -1,26 +1,35 @@
function tools_switch(state, tool) {
function switch_tool(state, item) {
const tool = item.getAttribute('data-tool');
if (state.tools.active_element) {
state.tools.active_element.classList.remove('active');
}
state.tools.active = tool;
state.tools.active_element = document.querySelector(`.tool[data-tool="${tool}"]`);
state.tools.active_element = item;
state.tools.active_element.classList.add('active');
}
function init_tools(state, context) {
const pencil = document.querySelector('.tool[data-tool="pencil"]');
const ruler = document.querySelector('.tool[data-tool="ruler"]');
const eraser = document.querySelector('.tool[data-tool="eraser"]');
const undo = document.querySelector('.tool[data-tool="undo"]');
pencil.addEventListener('click', () => tools_switch(state, 'pencil'));
ruler.addEventListener('click', () => tools_switch(state, 'ruler'));
eraser.addEventListener('click', () => tools_switch(state, 'eraser'));
undo.addEventListener('click', () => {
pop_stroke(state, context);
window.requestAnimationFrame(() => draw(state, context));
});
tools_switch(state, 'pencil');
function switch_color(state, item) {
const color = item.getAttribute('data-color');
if (state.colors.active_element) {
state.colors.active_element.classList.remove('active');
}
state.colors.active = color_to_u32(color);
state.colors.active_element = item;
state.colors.active_element.classList.add('active');
}
function init_tools(state) {
const tools = document.querySelectorAll('.tools .tool');
const colors = document.querySelectorAll('.pallete .color');
tools.forEach((item) => { item.addEventListener('click', () => switch_tool(state, item)); });
colors.forEach((item) => { item.addEventListener('click', () => switch_color(state, item)); });
// TODO: from localstorage
switch_tool(state, document.querySelector('.tool[data-tool="pencil"]'));
switch_color(state, document.querySelector('.color[data-color="000000"]'));
}

8
client/webgl.js

@ -163,7 +163,6 @@ function main() { @@ -163,7 +163,6 @@ function main() {
'lsn': 0,
'server_lsn': 0,
'color': 0,
'stroke_width': 8,
'touch': {
@ -193,6 +192,11 @@ function main() { @@ -193,6 +192,11 @@ function main() {
'active_element': null,
},
'colors': {
'active': null,
'active_element': null,
},
'timers': {
'ws_reconnect': null,
},
@ -231,7 +235,7 @@ function main() { @@ -231,7 +235,7 @@ function main() {
init_webgl(state, context);
init_listeners(state, context);
init_tools(state, context);
init_tools(state);
ws_connect(state, context, true);

22
client/webgl_geometry.js

@ -141,15 +141,28 @@ function recompute_dynamic_data(state, context) { @@ -141,15 +141,28 @@ function recompute_dynamic_data(state, context) {
context.dynamic_positions_f32 = new Float32Array(total_dynamic_length);
context.dynamic_colors_u8 = new Uint8Array(total_dynamic_length / 2 * 3);
// TODO: preview stroke colors for other users
context.dynamic_colors_u8.fill(0);
let at = 0;
for (const player_id in context.dynamic_positions) {
context.dynamic_positions_f32.set(context.dynamic_positions[player_id], at);
if (parseInt(player_id) === state.me) {
const color_u32 = state.colors.active;
const r = (color_u32 >> 16) & 0xFF;
const g = (color_u32 >> 8) & 0xFF;
const b = color_u32 & 0xFF;
for (let i = 0; i < context.dynamic_positions[player_id].length; ++i) {
context.dynamic_colors_u8[at / 2 * 3 + i * 3 + 0] = r;
context.dynamic_colors_u8[at / 2 * 3 + i * 3 + 1] = g;
context.dynamic_colors_u8[at / 2 * 3 + i * 3 + 2] = b;
}
}
at += context.dynamic_positions[player_id].length;
}
// TODO: preview stroke colors
context.dynamic_colors_u8.fill(0);
}
function update_dynamic_stroke(state, context, player_id, point) {
@ -157,7 +170,7 @@ function update_dynamic_stroke(state, context, player_id, point) { @@ -157,7 +170,7 @@ function update_dynamic_stroke(state, context, player_id, point) {
state.current_strokes[player_id] = {
'points': [],
'width': 8, // TODO
'color': 0, // TODO
'color': state.colors.active,
};
context.dynamic_positions[player_id] = [];
@ -177,6 +190,7 @@ function update_dynamic_stroke(state, context, player_id, point) { @@ -177,6 +190,7 @@ function update_dynamic_stroke(state, context, player_id, point) {
function clear_dynamic_stroke(state, context, player_id) {
if (player_id in state.current_strokes) {
state.current_strokes[player_id].points.length = 0;
state.current_strokes[player_id].color = state.colors.active;
context.dynamic_positions[player_id].length = 0;
recompute_dynamic_data(state, context);
}

5
client/webgl_listeners.js

@ -102,7 +102,7 @@ function mouseup(e, state, context) { @@ -102,7 +102,7 @@ function mouseup(e, state, context) {
if (state.drawing) {
const stroke = {
'color': state.color,
'color': state.colors.active,
'width': state.stroke_width,
'points': process_stroke(state.current_strokes[state.me].points),
'user_id': state.me,
@ -229,6 +229,7 @@ function touchmove(e, state, context) { @@ -229,6 +229,7 @@ function touchmove(e, state, context) {
if (state.touch.buffered.length > 0) {
clear_dynamic_stroke(state, context, state.me);
// BUG: can't see these on other clients!!
for (const p of state.touch.buffered) {
update_dynamic_stroke(state, context, state.me, p);
fire_event(predraw_event(canvasp.x, canvasp.y));
@ -314,7 +315,7 @@ function touchend(e, state, context) { @@ -314,7 +315,7 @@ function touchend(e, state, context) {
// await queue_event(event);
const stroke = {
'color': state.color,
'color': state.colors.active,
'width': state.stroke_width,
'points': process_stroke(state.current_strokes[state.me].points),
'user_id': state.me,

Loading…
Cancel
Save