|
|
@ -1,3 +1,22 @@ |
|
|
|
|
|
|
|
let traces = {}; |
|
|
|
|
|
|
|
let config = {}; |
|
|
|
|
|
|
|
let raster_tile = {'x': 0, 'y': 0}; |
|
|
|
|
|
|
|
let numbers_rasterized = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
onmessage = (e) => { |
|
|
|
|
|
|
|
const msg = e.data; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (msg.type === 'init') { |
|
|
|
|
|
|
|
config = msg.config; |
|
|
|
|
|
|
|
} else if (msg.type === 'import') { |
|
|
|
|
|
|
|
const text = msg.text; |
|
|
|
|
|
|
|
if (parse(text)) { |
|
|
|
|
|
|
|
traces['0'].geo = generate('0'); |
|
|
|
|
|
|
|
postMessage({'type': 'trace', 'data': traces['0']}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function parse(text) { |
|
|
|
function parse(text) { |
|
|
|
// https://github.com/shioyadan/Konata/blob/master/docs/kanata-log-format.md
|
|
|
|
// https://github.com/shioyadan/Konata/blob/master/docs/kanata-log-format.md
|
|
|
|
|
|
|
|
|
|
|
@ -12,6 +31,13 @@ function parse(text) { |
|
|
|
//console.log(text);
|
|
|
|
//console.log(text);
|
|
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < text.length; ++i) { |
|
|
|
for (let i = 0; i < text.length; ++i) { |
|
|
|
|
|
|
|
const last_percent = Math.round((i - 1) / text.length * 100); |
|
|
|
|
|
|
|
const this_percent = Math.round(i / text.length * 100); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this_percent != last_percent) { |
|
|
|
|
|
|
|
postMessage({'type': 'progress_parse', 'data': this_percent}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (text[i] === '\n') { |
|
|
|
if (text[i] === '\n') { |
|
|
|
// TODO: speed
|
|
|
|
// TODO: speed
|
|
|
|
const line_copy = text.substring(line_start, i); |
|
|
|
const line_copy = text.substring(line_start, i); |
|
|
@ -163,18 +189,15 @@ function parse(text) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
traces['0'] = { |
|
|
|
traces['0'] = { |
|
|
|
// The fact these are sorted is used extensively over the code
|
|
|
|
// The fact these are sorted is used extensively over the code
|
|
|
|
'raw': Object.values(instructions).sort((a, b) => a.cycle - b.cycle), |
|
|
|
'raw': Object.values(instructions).sort((a, b) => a.cycle - b.cycle), |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
traces['0'].geo = generate('0'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const after = performance.now(); |
|
|
|
const after = performance.now(); |
|
|
|
console.log(`Parsed in ${Math.round(after - before)}ms`); |
|
|
|
console.log(`Parsed in ${Math.round(after - before)}ms`); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -195,3 +218,192 @@ function assert_arglenmin(args, arglen, command) { |
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let colors = {}; |
|
|
|
|
|
|
|
let rasterized = {}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// https://stackoverflow.com/a/17243070
|
|
|
|
|
|
|
|
function hsv_to_rgb(h, s, v) { |
|
|
|
|
|
|
|
let r, g, b; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const i = Math.floor(h * 6); |
|
|
|
|
|
|
|
const f = h * 6 - i; |
|
|
|
|
|
|
|
const p = v * (1 - s); |
|
|
|
|
|
|
|
const q = v * (1 - f * s); |
|
|
|
|
|
|
|
const t = v * (1 - (1 - f) * s); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (i % 6) { |
|
|
|
|
|
|
|
case 0: r = v, g = t, b = p; break; |
|
|
|
|
|
|
|
case 1: r = q, g = v, b = p; break; |
|
|
|
|
|
|
|
case 2: r = p, g = v, b = t; break; |
|
|
|
|
|
|
|
case 3: r = p, g = q, b = v; break; |
|
|
|
|
|
|
|
case 4: r = t, g = p, b = v; break; |
|
|
|
|
|
|
|
case 5: r = v, g = p, b = q; break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return [ |
|
|
|
|
|
|
|
Math.round(r * 255), |
|
|
|
|
|
|
|
Math.round(g * 255), |
|
|
|
|
|
|
|
Math.round(b * 255) |
|
|
|
|
|
|
|
]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function get_color(stage_name) { |
|
|
|
|
|
|
|
if (stage_name in config.predefined_colors) { |
|
|
|
|
|
|
|
return config.predefined_colors[stage_name]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (stage_name in colors) { |
|
|
|
|
|
|
|
return colors[stage_name]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
colors[stage_name] = hsv_to_rgb(Math.random(), 0.56, 0.56); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return colors[stage_name]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function rasterize_and_pack(text, cycles) { |
|
|
|
|
|
|
|
// TODO: handle texture is full or stuff don't fit (unlikely)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const key = text; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (key in rasterized) { |
|
|
|
|
|
|
|
return rasterized[key]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const u = raster_tile.x * config.w / config.raster_texture_size; |
|
|
|
|
|
|
|
const v = raster_tile.y * config.h / config.raster_texture_size; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
postMessage({'type': 'rasterize', 'data': { 'text': text, 'at': {'x': raster_tile.x, 'y': raster_tile.y}}}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
raster_tile.x += 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (raster_tile.x === config.raster_texture_size / config.w) { |
|
|
|
|
|
|
|
raster_tile.x = 0; |
|
|
|
|
|
|
|
raster_tile.y += 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rasterized[key] = [u, v]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (cycles > 1) { |
|
|
|
|
|
|
|
for (let i = numbers_rasterized + 1; i <= cycles; ++i) { |
|
|
|
|
|
|
|
const u = raster_tile.x * config.w / config.raster_texture_size; |
|
|
|
|
|
|
|
const v = raster_tile.y * config.h / config.raster_texture_size; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
postMessage({'type': 'rasterize', 'data': { 'text': i, 'at': {'x': raster_tile.x, 'y': raster_tile.y}}}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
raster_tile.x += 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (raster_tile.x === config.raster_texture_size / config.w) { |
|
|
|
|
|
|
|
raster_tile.x = 0; |
|
|
|
|
|
|
|
raster_tile.y += 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rasterized[i] = [u, v]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (cycles > numbers_rasterized) { |
|
|
|
|
|
|
|
numbers_rasterized = cycles; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return [u, v]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function pack_instruction(instruction, positions, sizes, colors, uvs, starts, y) { |
|
|
|
|
|
|
|
starts.push(positions.length); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < instruction.lanes['0'].length; ++i) { |
|
|
|
|
|
|
|
const stage = instruction.lanes['0'][i]; |
|
|
|
|
|
|
|
let stage_cycles; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (i < instruction.lanes['0'].length - 1) { |
|
|
|
|
|
|
|
const next_stage = instruction.lanes['0'][i + 1]; |
|
|
|
|
|
|
|
stage_cycles = next_stage.c - stage.c; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
stage_cycles = instruction.retcyc - stage.c; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let [r, g, b] = get_color(stage.name); |
|
|
|
|
|
|
|
let a = 255; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!instruction.retired) { |
|
|
|
|
|
|
|
a = 80; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [u, v] = rasterize_and_pack(stage.name, stage_cycles); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sizes.push(stage_cycles * config.w + (stage_cycles - 1) * config.padding, 1 * config.h); |
|
|
|
|
|
|
|
positions.push(config.w * stage.c + config.padding * (stage.c - 1), config.h * y + config.padding * (y - 1)); |
|
|
|
|
|
|
|
colors.push(r, g, b, a); |
|
|
|
|
|
|
|
uvs.push(u, v); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return instruction.lanes['0'].length; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function generate(trace_id) { |
|
|
|
|
|
|
|
const before = performance.now(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const result = { |
|
|
|
|
|
|
|
'count': 0, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const positions = []; |
|
|
|
|
|
|
|
const sizes = []; |
|
|
|
|
|
|
|
const colors = []; |
|
|
|
|
|
|
|
const uvs = []; |
|
|
|
|
|
|
|
const starts = []; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let instructions = {}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (trace_id in traces) { |
|
|
|
|
|
|
|
instructions = traces[trace_id].raw; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let y = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < instructions.length; ++i) { |
|
|
|
|
|
|
|
const last_percent = Math.round((i - 1) / instructions.length * 100); |
|
|
|
|
|
|
|
const this_percent = Math.round(i / instructions.length * 100); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this_percent !== last_percent) { |
|
|
|
|
|
|
|
postMessage({'type': 'progress_generate', 'data': this_percent}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const instruction = instructions[i]; |
|
|
|
|
|
|
|
// TODO: make all quads same size, abuse this fact
|
|
|
|
|
|
|
|
result.count += pack_instruction(instruction, positions, sizes, colors, uvs, starts, y); |
|
|
|
|
|
|
|
if (config.limit > 0 && result.count >= config.limit) { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
++y; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
starts.push(positions.length); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (config.show_texture) { |
|
|
|
|
|
|
|
result.pos = new Float32Array([0, 0]); |
|
|
|
|
|
|
|
result.size = new Float32Array([config.raster_texture_size, config.raster_texture_size]); |
|
|
|
|
|
|
|
result.color = new Uint8Array([0, 0, 0, 255]); |
|
|
|
|
|
|
|
result.uv = new Float32Array([0, 0]); |
|
|
|
|
|
|
|
result.count = 1; |
|
|
|
|
|
|
|
result.trace_id = trace_id; |
|
|
|
|
|
|
|
result.uploaded = false; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
result.pos = new Float32Array(positions); |
|
|
|
|
|
|
|
result.size = new Float32Array(sizes); |
|
|
|
|
|
|
|
result.color = new Uint8Array(colors); |
|
|
|
|
|
|
|
result.uv = new Float32Array(uvs); |
|
|
|
|
|
|
|
result.trace_id = trace_id; |
|
|
|
|
|
|
|
result.uploaded = false; |
|
|
|
|
|
|
|
result.start = new Int32Array(starts); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const after = performance.now(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`Generated geometry in ${Math.round(after - before)}ms`); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|