Browse Source

More betterer active image highlight

ssao
A.Olokhtonov 5 months ago
parent
commit
66e84c1a50
  1. 3
      README.txt
  2. 4
      client/default.css
  3. 52
      client/icons/pointer.svg
  4. 1
      client/index.html
  5. 2
      client/index.js
  6. 13
      client/tools.js
  7. 14
      client/webgl_draw.js
  8. 64
      client/webgl_listeners.js
  9. 15
      client/webgl_shaders.js

3
README.txt

@ -30,6 +30,9 @@ Release: @@ -30,6 +30,9 @@ Release:
- Do NOT use session id as player id LUL
- Save events to indexeddb (as some kind of a blob), restore on reconnect and page reload
- Local prediction for tools!
- Immediately commit a stroke to the canvas, change order if earlier strokes arrive
- Show my own image immediately, show placeholders while images are loading (add bitmap size to event)
- undo immediately, this one can not arrive out of order, because noone else is going to undo MY actions
* Missing features I do not consider bonus
+ Player pointers
+ Pretty player pointers

4
client/default.css

@ -43,6 +43,10 @@ canvas { @@ -43,6 +43,10 @@ canvas {
cursor: url('icons/crosshair.svg') 16 16, crosshair;
}
canvas.tool-pointer {
cursor: default;
}
canvas.picker {
cursor: url('icons/picker.svg') 0 19, crosshair;
}

52
client/icons/pointer.svg

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="32"
viewBox="0 0 8.4666665 8.4666666"
version="1.1"
id="svg5"
sodipodi:docname="pointer.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
showgrid="true"
inkscape:zoom="13.455443"
inkscape:cx="4.2733635"
inkscape:cy="26.086097"
inkscape:window-width="2558"
inkscape:window-height="1412"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="layer1">
<inkscape:grid
type="xygrid"
id="grid1775" />
</sodipodi:namedview>
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.264583px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 2.5420359,7.0728549 2.0552699,0.9380846 7.1247537,4.4270217 5.0270833,5.0270833 6.0854165,6.8601704 5.1688732,7.3893369 4.1105397,5.5562497 Z"
id="path1887"
sodipodi:nodetypes="cccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

1
client/index.html

@ -234,6 +234,7 @@ @@ -234,6 +234,7 @@
<div class="tools-wrapper">
<div class="tools">
<div class="tool" data-tool="pointer"><img draggable="false" src="icons/pointer.svg"></div>
<div class="tool active" data-tool="pencil"><img draggable="false" src="icons/pen.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>

2
client/index.js

@ -233,7 +233,7 @@ async function main() { @@ -233,7 +233,7 @@ async function main() {
'wasm': {},
'background_pattern': 'grid',
'background_pattern': 'dots',
};
const context = {

13
client/tools.js

@ -10,9 +10,22 @@ function switch_tool(state, item) { @@ -10,9 +10,22 @@ function switch_tool(state, item) {
state.tools.active_element.classList.remove('active');
}
const old_class = 'tool-' + state.tools.active;
const new_class = 'tool-' + tool;
document.querySelector('canvas').classList.remove(old_class);
state.tools.active = tool;
state.tools.active_element = item;
state.tools.active_element.classList.add('active');
document.querySelector('canvas').classList.add(new_class);
if (tool === 'pointer' || tool === 'eraser') {
document.querySelector('.brush-dom').classList.add('dhide');
} else {
document.querySelector('.brush-dom').classList.remove('dhide');
}
}
function select_color(state, item, color_u32) {

14
client/webgl_draw.js

@ -226,20 +226,22 @@ async function draw(state, context, animate, ts) { @@ -226,20 +226,22 @@ async function draw(state, context, animate, ts) {
gl.vertexAttribPointer(locations['a_pos'], 2, gl.FLOAT, false, 2 * 4, 0);
for (const entry of context.images) {
if (state.active_image === entry.key) {
//gl.uniform1i(locations['u_active'], 1);
} else {
//gl.uniform1i(locations['u_active'], 0);
}
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_texture'], 0); // Only 1 active texture for each drawcall
gl.uniform1i(locations['u_solid'], 0);
gl.bindTexture(gl.TEXTURE_2D, entry.texture);
gl.drawArrays(gl.TRIANGLES, offset, 6);
// Highlight active image
if (entry.key === context.active_image) {
gl.uniform1i(locations['u_solid'], 1);
gl.uniform4f(locations['u_color'], 0.133 * 0.5, 0.545 * 0.5, 0.902 * 0.5, 0.5);
gl.drawArrays(gl.TRIANGLES, offset, 6);
}
offset += 6;
}
}

64
client/webgl_listeners.js

@ -107,21 +107,25 @@ function zenmode() { @@ -107,21 +107,25 @@ function zenmode() {
}
function enter_picker_mode(state, context) {
document.querySelector('canvas').classList.add('picker');
document.querySelector('.picker-preview-outer').classList.remove('dhide');
document.querySelector('.brush-dom').classList.add('dhide');
state.colorpicking = true;
if (state.tools.active === 'pencil') { // or other drawing tools
document.querySelector('canvas').classList.add('picker');
document.querySelector('.picker-preview-outer').classList.remove('dhide');
document.querySelector('.brush-dom').classList.add('dhide');
state.colorpicking = true;
const canvasp = screen_to_canvas(state, state.cursor);
update_color_picker_color(state, context, canvasp);
const canvasp = screen_to_canvas(state, state.cursor);
update_color_picker_color(state, context, canvasp);
}
}
function exit_picker_mode(state) {
document.querySelector('canvas').classList.remove('picker');
document.querySelector('.picker-preview-outer').classList.add('dhide');
document.querySelector('.brush-dom').classList.remove('dhide');
state.colorpicking = false;
if (state.colorpicking) {
document.querySelector('canvas').classList.remove('picker');
document.querySelector('.picker-preview-outer').classList.add('dhide');
document.querySelector('.brush-dom').classList.remove('dhide');
state.colorpicking = false;
}
}
async function paste(e, state, context) {
@ -160,7 +164,7 @@ function keyup(e, state, context) { @@ -160,7 +164,7 @@ function keyup(e, state, context) {
state.moving = false;
context.canvas.classList.remove('movemode');
} else if (e.code === 'ControlLeft' || e.code === 'ControlRight') {
exit_picker_mode(state);
exit_picker_mode(state);exit_picker_mode
} else if (e.code === 'KeyZ') {
state.zoomdown = false;
}
@ -170,21 +174,6 @@ function mousedown(e, state, context) { @@ -170,21 +174,6 @@ function mousedown(e, state, context) {
const screenp = {'x': window.devicePixelRatio * e.clientX, 'y': window.devicePixelRatio * e.clientY};
const canvasp = screen_to_canvas(state, screenp);
if (e.button === 2) {
// Right click on image to select it
const image_event = image_at(state, canvasp.x, canvasp.y);
if (image_event) {
context.active_image = image_event.image_id;
} else {
context.active_image = null;
}
schedule_draw(state, context);
return;
}
if (e.button !== 0 && e.button !== 1) {
return;
}
@ -203,15 +192,6 @@ function mousedown(e, state, context) { @@ -203,15 +192,6 @@ function mousedown(e, state, context) {
return;
}
if (context.active_image) {
// Move selected image with left click
const image_event = image_at(state, canvasp.x, canvasp.y);
if (image_event && image_event.image_id === context.active_image) {
state.moving_image = image_event;
return;
}
}
if (state.spacedown || e.button === 1) {
state.moving = true;
context.canvas.classList.add('moving');
@ -236,6 +216,16 @@ function mousedown(e, state, context) { @@ -236,6 +216,16 @@ function mousedown(e, state, context) {
} else if (state.tools.active === 'eraser') {
state.erasing = true;
} else if (state.tools.active === 'pointer') {
const image_event = image_at(state, canvasp.x, canvasp.y);
if (image_event) {
context.active_image = image_event.image_id;
} else {
context.active_image = null;
}
schedule_draw(state, context);
}
}
@ -412,7 +402,7 @@ function mouseleave(e, state, context) { @@ -412,7 +402,7 @@ function mouseleave(e, state, context) {
context.canvas.classList.remove('movemode');
}
exit_picker_mode(state);
//exit_picker_mode(state);
// something else?
}

15
client/webgl_shaders.js

@ -207,8 +207,6 @@ const tquad_vs_src = `#version 300 es @@ -207,8 +207,6 @@ const tquad_vs_src = `#version 300 es
void main() {
vec2 screen01 = (a_pos * u_scale + u_translation) / u_res;
vec2 screen02 = screen01 * 2.0;
screen02.y = 2.0 - screen02.y;
vec2 screen11 = screen02 - 1.0;
int vertex_index = gl_VertexID % 6;
@ -222,6 +220,9 @@ const tquad_vs_src = `#version 300 es @@ -222,6 +220,9 @@ const tquad_vs_src = `#version 300 es
v_texcoord = vec2(1.0, 1.0);
}
screen02.y = 2.0 - screen02.y;
vec2 screen11 = screen02 - 1.0;
gl_Position = vec4(screen11, 0, 1);
}
`;
@ -232,11 +233,17 @@ const tquad_fs_src = `#version 300 es @@ -232,11 +233,17 @@ const tquad_fs_src = `#version 300 es
in vec2 v_texcoord;
uniform sampler2D u_texture;
uniform int u_solid;
uniform vec4 u_color;
layout(location = 0) out vec4 FragColor;
void main() {
FragColor = texture(u_texture, v_texcoord);
if (u_solid == 0) {
FragColor = texture(u_texture, v_texcoord);
} else {
FragColor = u_color;
}
}
`;
@ -405,6 +412,8 @@ function init_webgl(state, context) { @@ -405,6 +412,8 @@ function init_webgl(state, context) {
'u_scale': gl.getUniformLocation(context.programs['image'], 'u_scale'),
'u_translation': gl.getUniformLocation(context.programs['image'], 'u_translation'),
'u_texture': gl.getUniformLocation(context.programs['image'], 'u_texture'),
'u_solid': gl.getUniformLocation(context.programs['image'], 'u_solid'),
'u_color': gl.getUniformLocation(context.programs['image'], 'u_color'),
};
context.locations['debug'] = {

Loading…
Cancel
Save