Browse Source

HSV random colors, bring back fade, fix alpha in shader, rasterize numbers to separate texture, start with number quads

master
Aleksey Olokhtonov 4 months ago
parent
commit
31584dcf91
  1. 88
      geometry.js
  2. 52
      render.js

88
geometry.js

@ -1,6 +1,31 @@
let colors = {}; let colors = {};
let rasterized = {}; 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) { function get_color(stage_name) {
if (stage_name in config.predefined_colors) { if (stage_name in config.predefined_colors) {
return config.predefined_colors[stage_name]; return config.predefined_colors[stage_name];
@ -10,11 +35,7 @@ function get_color(stage_name) {
return colors[stage_name]; return colors[stage_name];
} }
const r = Math.floor(Math.random() * 155); colors[stage_name] = hsv_to_rgb(Math.random(), 0.56, 0.56);
const g = Math.floor(Math.random() * 155);
const b = Math.floor(Math.random() * 155);
colors[stage_name] = [ 100 + r, 100 + g, 100 + b ];
return colors[stage_name]; return colors[stage_name];
} }
@ -22,21 +43,12 @@ function get_color(stage_name) {
function rasterize_and_pack(text, cycles) { function rasterize_and_pack(text, cycles) {
// TODO: handle texture is full or stuff don't fit (unlikely) // TODO: handle texture is full or stuff don't fit (unlikely)
const key = text + '@' + cycles; const key = text;
if (key in rasterized) { if (key in rasterized) {
return rasterized[key]; return rasterized[key];
} }
let cycles_total_padding = (cycles - 1) * config.padding;
let bonus_cells = Math.ceil(cycles_total_padding / config.w);
const tiles_needed = 1; // cycles - 1 + 1 + bonus_cells; // stage name + count cycles from one
if (tiles_needed > config.raster_texture_size / config.w - raster_tile.x) {
raster_tile.x = 0;
raster_tile.y += 1;
}
const u = raster_tile.x * config.w / config.raster_texture_size; const u = raster_tile.x * config.w / config.raster_texture_size;
const v = raster_tile.y * config.h / config.raster_texture_size; const v = raster_tile.y * config.h / config.raster_texture_size;
@ -50,18 +62,42 @@ function rasterize_and_pack(text, cycles) {
); );
raster_tile.x += 1; raster_tile.x += 1;
/*
raster_tile.x += cycles + bonus_cells;
if (raster_tile.x === config.raster_texture_size / config.w) { if (raster_tile.x === config.raster_texture_size / config.w) {
raster_tile.x = 0; raster_tile.x = 0;
raster_tile.y += 1; raster_tile.y += 1;
} }
*/
rasterized[key] = [u, v]; rasterized[key] = [u, v];
if (cycles > 1) {
gl.bindTexture(gl.TEXTURE_2D, textures['numbers']);
for (let i = numbers_rasterized + 1; i <= cycles; ++i) {
const u = number_tile.x * config.w / config.raster_texture_size;
const v = number_tile.y * config.h / config.raster_texture_size;
rasterize(i);
gl.texSubImage2D(gl.TEXTURE_2D, 0,
number_tile.x * config.w, number_tile.y * config.h,
config.w, config.h,
gl.RGBA, gl.UNSIGNED_BYTE,
c2d.canvas
);
number_tile.x += 1;
if (number_tile.x === config.raster_texture_size / config.w) {
number_tile.x = 0;
number_tile.y += 1;
}
rasterized[i] = [u, v];
}
if (cycles > numbers_rasterized) {
numbers_rasterized = cycles;
}
}
return [u, v]; return [u, v];
} }
@ -83,10 +119,7 @@ function pack_instruction(instruction, positions, sizes, colors, uvs, starts, y)
let a = 255; let a = 255;
if (!instruction.retired) { if (!instruction.retired) {
r = Math.max(50, r - 50); a = 80;
g = Math.max(50, g - 50);
b = Math.max(50, b - 50);
a = 100;
} }
const [u, v] = rasterize_and_pack(stage.name, stage_cycles); const [u, v] = rasterize_and_pack(stage.name, stage_cycles);
@ -123,6 +156,7 @@ function generate(trace_id) {
for (let i = 0; i < instructions.length; ++i) { for (let i = 0; i < instructions.length; ++i) {
const instruction = instructions[i]; const instruction = instructions[i];
// TODO: make all quads same size, abuse this fact
result.count += pack_instruction(instruction, positions, sizes, colors, uvs, starts, y); result.count += pack_instruction(instruction, positions, sizes, colors, uvs, starts, y);
if (config.limit > 0 && result.count >= config.limit) { if (config.limit > 0 && result.count >= config.limit) {
break; break;
@ -132,7 +166,7 @@ function generate(trace_id) {
starts.push(positions.length); starts.push(positions.length);
if (false) { if (config.show_texture) {
result.pos = new Float32Array([0, 0]); result.pos = new Float32Array([0, 0]);
result.size = new Float32Array([config.raster_texture_size, config.raster_texture_size]); result.size = new Float32Array([config.raster_texture_size, config.raster_texture_size]);
result.color = new Uint8Array([0, 0, 0, 255]); result.color = new Uint8Array([0, 0, 0, 255]);
@ -158,6 +192,10 @@ function generate(trace_id) {
} }
function clip(quads) { function clip(quads) {
if (config.show_texture) {
return quads;
}
const tl = screen_to_canvas({'x': 0, 'y': 0}); const tl = screen_to_canvas({'x': 0, 'y': 0});
const br = screen_to_canvas({'x': 0, 'y': canvas.height}); const br = screen_to_canvas({'x': 0, 'y': canvas.height});

52
render.js

@ -29,6 +29,7 @@ let config = {
zoom_delta: 0.05, zoom_delta: 0.05,
raster_texture_size: 4096, raster_texture_size: 4096,
max_zoom_level: 0, max_zoom_level: 0,
show_texture: false,
}; };
let canvas = null; let canvas = null;
@ -43,7 +44,9 @@ let zoom_screenp = { 'x': 0, 'y': 0 };
let last_frame_dt = 0; let last_frame_dt = 0;
let last_frame_ts = 0; let last_frame_ts = 0;
let raster_tile = { 'x': 0, 'y': 0 }; let raster_tile = { 'x': 0, 'y': 0 };
let number_tile = { 'x': 0, 'y': 0 };
let spacedown = false; let spacedown = false;
let numbers_rasterized = 0;
const tquad_vs_src = `#version 300 es const tquad_vs_src = `#version 300 es
in vec2 a_pos; in vec2 a_pos;
@ -56,6 +59,7 @@ const tquad_vs_src = `#version 300 es
uniform float u_scale; uniform float u_scale;
uniform vec2 u_textile; uniform vec2 u_textile;
uniform vec2 u_tile; uniform vec2 u_tile;
uniform int u_single;
out vec4 v_color; out vec4 v_color;
out vec2 v_uv; out vec2 v_uv;
@ -72,7 +76,11 @@ const tquad_vs_src = `#version 300 es
} }
vec2 cycles = a_size / u_tile; vec2 cycles = a_size / u_tile;
vec2 tt = u_textile / u_tile; vec2 size = a_size;
if (u_single != 0) {
size = u_tile;
}
if (vertex_index == 0) { if (vertex_index == 0) {
// "top left" aka "p1" // "top left" aka "p1"
@ -80,16 +88,16 @@ const tquad_vs_src = `#version 300 es
uv = a_uv; uv = a_uv;
} 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, 0); corner = a_pos + vec2(size.x, 0);
uv = a_uv + vec2(u_textile.x * cycles.x, 0); uv = a_uv + vec2(u_textile.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(0, a_size.y); corner = a_pos + vec2(0, size.y);
uv = a_uv + vec2(0, u_textile.y * cycles.y); uv = a_uv + vec2(0, u_textile.y);
} else { } else {
// "bottom right" aka "p4" // "bottom right" aka "p4"
corner = a_pos + a_size; corner = a_pos + size;
uv = a_uv + u_textile * cycles; uv = a_uv + u_textile;
} }
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;
@ -109,13 +117,18 @@ const tquad_fs_src = `#version 300 es
uniform sampler2D u_texture; uniform sampler2D u_texture;
uniform float u_fade; uniform float u_fade;
uniform int u_solid;
layout(location = 0) out vec4 FragColor; layout(location = 0) out vec4 FragColor;
void main() { void main() {
vec4 text = texture(u_texture, v_uv); if (u_solid != 0) {
text.a = min(min(text.a, v_color.a), u_fade); FragColor = vec4(v_color.rgb * v_color.a, v_color.a);
FragColor = vec4(text.rgb * text.a + v_color.rgb, 1.0); } else {
vec4 text = texture(u_texture, v_uv);
float a = min(u_fade, min(text.a, v_color.a));
FragColor = vec4(text.rgb * a, a);
}
} }
`; `;
@ -177,6 +190,8 @@ function draw(ts, animation) {
gl.uniform1i(program.locations['u_texture'], textures['raster']); gl.uniform1i(program.locations['u_texture'], textures['raster']);
gl.uniform2f(program.locations['u_tile'], config.w, config.h); gl.uniform2f(program.locations['u_tile'], config.w, config.h);
gl.uniform1f(program.locations['u_fade'], fade); gl.uniform1f(program.locations['u_fade'], fade);
gl.uniform1i(program.locations['u_solid'], 1);
gl.uniform1i(program.locations['u_single'], 0);
gl.enableVertexAttribArray(program.locations['a_pos']); gl.enableVertexAttribArray(program.locations['a_pos']);
gl.enableVertexAttribArray(program.locations['a_size']); gl.enableVertexAttribArray(program.locations['a_size']);
@ -193,9 +208,15 @@ function draw(ts, animation) {
gl.vertexAttribDivisor(program.locations['a_color'], 1); gl.vertexAttribDivisor(program.locations['a_color'], 1);
gl.vertexAttribDivisor(program.locations['a_uv'], 1); gl.vertexAttribDivisor(program.locations['a_uv'], 1);
gl.bindTexture(gl.TEXTURE_2D, textures['raster']);
gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, clipped.count); gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, clipped.count);
if (fade > 0) {
gl.bindTexture(gl.TEXTURE_2D, textures['raster']);
gl.uniform1i(program.locations['u_solid'], 0);
gl.uniform1i(program.locations['u_single'], 1);
gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, clipped.count);
}
gl.vertexAttribDivisor(program.locations['a_pos'], 0); gl.vertexAttribDivisor(program.locations['a_pos'], 0);
gl.vertexAttribDivisor(program.locations['a_size'], 0); gl.vertexAttribDivisor(program.locations['a_size'], 0);
gl.vertexAttribDivisor(program.locations['a_color'], 0); gl.vertexAttribDivisor(program.locations['a_color'], 0);
@ -278,8 +299,12 @@ function init_webgl() {
textures = { textures = {
'raster': gl.createTexture(), 'raster': gl.createTexture(),
'numbers': gl.createTexture(),
}; };
gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
const zeroes = new Uint8Array(config.raster_texture_size * config.raster_texture_size * 4); const zeroes = new Uint8Array(config.raster_texture_size * config.raster_texture_size * 4);
gl.bindTexture(gl.TEXTURE_2D, textures['raster']); gl.bindTexture(gl.TEXTURE_2D, textures['raster']);
@ -287,6 +312,11 @@ function init_webgl() {
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, config.raster_texture_size, config.raster_texture_size, 0, gl.RGBA, gl.UNSIGNED_BYTE, zeroes); // fill the whole texture once with zeroes to kill a warning about a partial upload gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, config.raster_texture_size, config.raster_texture_size, 0, gl.RGBA, gl.UNSIGNED_BYTE, zeroes); // fill the whole texture once with zeroes to kill a warning about a partial upload
gl.bindTexture(gl.TEXTURE_2D, textures['numbers']);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, config.raster_texture_size, config.raster_texture_size, 0, gl.RGBA, gl.UNSIGNED_BYTE, zeroes); // fill the whole texture once with zeroes to kill a warning about a partial upload
const resize_canvas = (entries) => { const resize_canvas = (entries) => {
// https://www.khronos.org/webgl/wiki/HandlingHighDPI // https://www.khronos.org/webgl/wiki/HandlingHighDPI
const entry = entries[0]; const entry = entries[0];

Loading…
Cancel
Save