Browse Source

Proper map controls (pan + zoom)

master
A.Olokhtonov 4 months ago
parent
commit
02ce35e24f
  1. 1
      .gitignore
  2. 20
      geometry.js
  3. 67
      input.js
  4. 14
      math.js
  5. 70
      render.js

1
.gitignore vendored

@ -0,0 +1 @@
*.log

20
geometry.js

@ -1,6 +1,10 @@
let colors = {}; let colors = {};
function get_color(stage_name) { function get_color(stage_name) {
if (stage_name in config.predefined_colors) {
return config.predefined_colors[stage_name];
}
if (stage_name in colors) { if (stage_name in colors) {
return colors[stage_name]; return colors[stage_name];
} }
@ -9,7 +13,7 @@ function get_color(stage_name) {
const g = Math.floor(Math.random() * 155); const g = Math.floor(Math.random() * 155);
const b = Math.floor(Math.random() * 155); const b = Math.floor(Math.random() * 155);
colors[stage_name] = { 'r': 100 + r, 'g': 100 + g, 'b': 100 + b }; colors[stage_name] = [ 100 + r, 100 + g, 100 + b ];
return colors[stage_name]; return colors[stage_name];
} }
@ -45,13 +49,23 @@ function generate(trace_id) {
stage_cycles = instruction.retcyc - stage.c; stage_cycles = instruction.retcyc - stage.c;
} }
const color = get_color(stage.name); let [r, g, b] = get_color(stage.name);
if (!instruction.retired) {
r = Math.max(50, r - 50);
g = Math.max(50, g - 50);
b = Math.max(50, b - 50);
}
sizes.push(stage_cycles * config.w, 1 * config.h); sizes.push(stage_cycles * config.w, 1 * config.h);
positions.push(config.w * stage.c, config.h * y); positions.push(config.w * stage.c, config.h * y);
colors.push(color.r, color.g, color.b, 255); colors.push(r, g, b, 255);
result.count++; result.count++;
if (config.limit > 0 && result.count >= config.limit) {
break;
}
} }
++y; ++y;

67
input.js

@ -1,7 +1,13 @@
function init_listeners() { function init_listeners() {
document.querySelector('.main').addEventListener('dragover', cancel); document.querySelector('#c').addEventListener('dragover', cancel);
document.querySelector('.main').addEventListener('drop', drop); document.querySelector('#c').addEventListener('drop', drop);
document.querySelector('.main').addEventListener('click', debug); document.querySelector('#c').addEventListener('click', debug);
document.querySelector('#c').addEventListener('mousedown', mousedown);
document.querySelector('#c').addEventListener('mousemove', mousemove);
document.querySelector('#c').addEventListener('mouseup', mouseup);
document.querySelector('#c').addEventListener('mouseleave', mouseup);
document.querySelector('#c').addEventListener('wheel', wheel);
window.addEventListener('keydown', keydown); window.addEventListener('keydown', keydown);
window.addEventListener('keyup', keyup); window.addEventListener('keyup', keyup);
@ -16,24 +22,49 @@ function cancel(e) {
e.stopPropagation(); e.stopPropagation();
} }
function keydown(e) { function mousedown(e) {
if (e.code === 'ArrowLeft') { if (e.button === 1) {
offset.x += 10 / scale; moving = true;
} else if (e.code === 'ArrowRight') { return;
offset.x -= 10 / scale; }
} else if (e.code === 'ArrowDown') { }
offset.y -= 10 / scale;
} else if (e.code === 'ArrowUp') { function mousemove(e) {
offset.y += 10 / scale; let do_draw = false;
} else if (e.code === 'PageUp') {
scale *= 0.9; if (moving) {
} else if (e.code === 'PageDown') { offset.x += e.movementX;
scale *= 1.1; offset.y += e.movementY;
do_draw = true;
}
if (do_draw) {
schedule_draw();
}
}
function mouseup(e) {
if (e.button === 1 && moving) {
moving = false;
} }
}
function wheel(e) {
const screenp = {'x': window.devicePixelRatio * e.clientX, 'y': window.devicePixelRatio * e.clientY};
const zooming_in = e.deltaY < 0;
const level = zooming_in ? zoom_level + 2 : zoom_level - 2;
const dz = (zoom_level > 0 ? config.zoom_delta : -config.zoom_delta);
zoom_level = level;
zoom_target = Math.pow(1.0 + dz, Math.abs(zoom_level))
zoom_screenp = screenp;
schedule_draw(); schedule_draw();
} }
function keydown(e) {
}
function keyup(e) { function keyup(e) {
} }
@ -59,7 +90,9 @@ function drop(e) {
const upload_finished = () => { const upload_finished = () => {
const text = fr.result; const text = fr.result;
console.log('Finished. String length:', text.length); console.log('Finished. String length:', text.length);
parse(text); if (parse(text)) {
schedule_draw();
}
}; };
const upload_progress = (e) => { const upload_progress = (e) => {

14
math.js

@ -0,0 +1,14 @@
function screen_to_canvas(p) {
// should be called with coordinates obtained from MouseEvent.clientX/clientY * window.devicePixelRatio
const xc = (p.x - offset.x) / zoom;
const yc = (p.y - offset.y) / zoom;
return {'x': xc, 'y': yc};
}
function canvas_to_screen(state, p) {
const xs = (p.x * zoom + offset.x) / window.devicePixelRatio;
const ys = (p.y * zoom + offset.y) / window.devicePixelRatio;
return {'x': xs, 'y': ys};
}

70
render.js

@ -5,13 +5,39 @@ let config = {
bytes_per_quad: 20, bytes_per_quad: 20,
w: 24, w: 24,
h: 24, h: 24,
predefined_colors: {
'Np': [75, 62, 143],
'F': [62, 123, 143],
'Pd': [61, 142, 88],
'Dc': [109, 143, 61],
'Rn': [143, 102, 61],
'Ds': [142, 61, 95],
'Sc': [115, 61, 143],
'Is': [61, 81, 143],
'Rr': [61, 143, 129],
'X': [68, 143, 61],
'Rw': [142, 142, 61],
'Cm': [61, 81, 143],
'Mt': [142, 142, 61],
'Ma': [143, 68, 61],
},
limit: -1,
zoom_delta: 0.05,
}; };
let canvas = null; let canvas = null;
let gl = null; let gl = null;
let gpu_timer_ext = null; let gpu_timer_ext = null;
let offset = { x: 0, y: 0 }; let offset = { x: 0, y: 0 };
let scale = 1; let moving = false;
let zoom = 1;
let zoom_target = 1.0;
let zoom_level = 0;
let zoom_screenp = { 'x': 0, 'y': 0 };
let last_frame_dt = 0;
let last_frame_ts = 0;
const tquad_vs_src = `#version 300 es const tquad_vs_src = `#version 300 es
in vec2 a_pos; in vec2 a_pos;
@ -30,16 +56,16 @@ const tquad_vs_src = `#version 300 es
if (vertex_index == 0) { if (vertex_index == 0) {
// "top left" aka "p1" // "top left" aka "p1"
corner = a_pos + vec2(1.0); corner = a_pos;
} else if (vertex_index == 1 || vertex_index == 5) { } else if (vertex_index == 1 || vertex_index == 5) {
// "top right" aka "p2" // "top right" aka "p2"
corner = a_pos + vec2(a_size.x - 1.0, 1.0); corner = a_pos + vec2(a_size.x, 0);
} else if (vertex_index == 2 || vertex_index == 4) { } else if (vertex_index == 2 || vertex_index == 4) {
// "bottom left" aka "p3" // "bottom left" aka "p3"
corner = a_pos + vec2(1.0, a_size.y - 1.0); corner = a_pos + vec2(0, a_size.y);
} else { } else {
// "bottom right" aka "p4" // "bottom right" aka "p4"
corner = a_pos + a_size - vec2(1.0); corner = a_pos + a_size;
} }
vec2 screen02 = (corner.xy * vec2(u_scale) + u_translation) / u_res * 2.0; vec2 screen02 = (corner.xy * vec2(u_scale) + u_translation) / u_res * 2.0;
@ -62,18 +88,21 @@ const tquad_fs_src = `#version 300 es
} }
`; `;
function schedule_draw() { function schedule_draw(animation = false) {
if (!timers.raf) { if (!timers.raf) {
window.requestAnimationFrame(draw); window.requestAnimationFrame((ts) => draw(ts, animation));
timers.raf = true; timers.raf = true;
} }
} }
function draw() { function draw(ts, animation) {
const dt = ts - last_frame_ts;
const cpu_before = performance.now(); const cpu_before = performance.now();
const width = window.innerWidth; const width = window.innerWidth;
const height = window.innerHeight; const height = window.innerHeight;
last_frame_ts = ts;
let query = null; let query = null;
if (gpu_timer_ext !== null) { if (gpu_timer_ext !== null) {
@ -82,7 +111,7 @@ function draw() {
} }
gl.viewport(0, 0, canvas.width, canvas.height); gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(0, 0, 0, 1); gl.clearColor(0.11, 0.11, 0.11, 1);
gl.clear(gl.COLOR_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT);
const quads = generate('0'); const quads = generate('0');
@ -99,7 +128,7 @@ function draw() {
gl.uniform2f(program.locations['u_res'], canvas.width, canvas.height); gl.uniform2f(program.locations['u_res'], canvas.width, canvas.height);
gl.uniform2f(program.locations['u_translation'], offset.x, offset.y); gl.uniform2f(program.locations['u_translation'], offset.x, offset.y);
gl.uniform1f(program.locations['u_scale'], scale); gl.uniform1f(program.locations['u_scale'], zoom);
gl.enableVertexAttribArray(program.locations['a_pos']); gl.enableVertexAttribArray(program.locations['a_pos']);
gl.enableVertexAttribArray(program.locations['a_size']); gl.enableVertexAttribArray(program.locations['a_size']);
@ -150,8 +179,29 @@ function draw() {
timers.raf = false; timers.raf = false;
console.log('Last CPU Frametime: ' + Math.round((cpu_after - cpu_before) * 100) / 100 + 'ms'); console.log('Last CPU Frametime: ' + Math.round((cpu_after - cpu_before) * 100) / 100 + 'ms');
if (zoom_target != zoom) {
update_canvas_zoom(zoom, zoom_target, animation ? dt : last_frame_dt);
schedule_draw(true);
}
last_frame_dt = dt;
} }
function update_canvas_zoom(current, target, dt) {
const rate = Math.min(1.0, dt / 16.66 * 0.3);
if (Math.abs(1.0 - current / target) > 0.01) {
zoom = current + (target - current) * rate;
} else {
zoom = target;
}
// https://gist.github.com/aolo2/a373363419bd5a9283977ab9f8841f78
const zc = zoom_screenp;
offset.x = zc.x - (zc.x - offset.x) * zoom / current;
offset.y = zc.y - (zc.y - offset.y) * zoom / current;
}
function init_webgl() { function init_webgl() {
canvas = document.querySelector('#c'); canvas = document.querySelector('#c');

Loading…
Cancel
Save