From 31584dcf9183cf245bea5c6a1c56dcba8db723f6 Mon Sep 17 00:00:00 2001 From: Aleksey Olokhtonov Date: Mon, 29 Jul 2024 11:25:31 +0300 Subject: [PATCH] HSV random colors, bring back fade, fix alpha in shader, rasterize numbers to separate texture, start with number quads --- geometry.js | 88 ++++++++++++++++++++++++++++++++++++++--------------- render.js | 52 ++++++++++++++++++++++++------- 2 files changed, 104 insertions(+), 36 deletions(-) diff --git a/geometry.js b/geometry.js index f37d7db..c69a0aa 100644 --- a/geometry.js +++ b/geometry.js @@ -1,6 +1,31 @@ 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]; @@ -10,11 +35,7 @@ function get_color(stage_name) { return colors[stage_name]; } - const r = Math.floor(Math.random() * 155); - const g = Math.floor(Math.random() * 155); - const b = Math.floor(Math.random() * 155); - - colors[stage_name] = [ 100 + r, 100 + g, 100 + b ]; + colors[stage_name] = hsv_to_rgb(Math.random(), 0.56, 0.56); return colors[stage_name]; } @@ -22,21 +43,12 @@ function get_color(stage_name) { function rasterize_and_pack(text, cycles) { // TODO: handle texture is full or stuff don't fit (unlikely) - const key = text + '@' + cycles; + const key = text; if (key in rasterized) { 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 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 += cycles + bonus_cells; - 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) { + 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]; } @@ -83,10 +119,7 @@ function pack_instruction(instruction, positions, sizes, colors, uvs, starts, y) let a = 255; if (!instruction.retired) { - r = Math.max(50, r - 50); - g = Math.max(50, g - 50); - b = Math.max(50, b - 50); - a = 100; + a = 80; } 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) { 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; @@ -132,7 +166,7 @@ function generate(trace_id) { starts.push(positions.length); - if (false) { + 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]); @@ -158,6 +192,10 @@ function generate(trace_id) { } function clip(quads) { + if (config.show_texture) { + return quads; + } + const tl = screen_to_canvas({'x': 0, 'y': 0}); const br = screen_to_canvas({'x': 0, 'y': canvas.height}); diff --git a/render.js b/render.js index a3c9e00..8e6627b 100644 --- a/render.js +++ b/render.js @@ -29,6 +29,7 @@ let config = { zoom_delta: 0.05, raster_texture_size: 4096, max_zoom_level: 0, + show_texture: false, }; let canvas = null; @@ -43,7 +44,9 @@ let zoom_screenp = { 'x': 0, 'y': 0 }; let last_frame_dt = 0; let last_frame_ts = 0; let raster_tile = { 'x': 0, 'y': 0 }; +let number_tile = { 'x': 0, 'y': 0 }; let spacedown = false; +let numbers_rasterized = 0; const tquad_vs_src = `#version 300 es in vec2 a_pos; @@ -56,6 +59,7 @@ const tquad_vs_src = `#version 300 es uniform float u_scale; uniform vec2 u_textile; uniform vec2 u_tile; + uniform int u_single; out vec4 v_color; out vec2 v_uv; @@ -72,7 +76,11 @@ const tquad_vs_src = `#version 300 es } 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) { // "top left" aka "p1" @@ -80,16 +88,16 @@ const tquad_vs_src = `#version 300 es uv = a_uv; } else if (vertex_index == 1 || vertex_index == 5) { // "top right" aka "p2" - corner = a_pos + vec2(a_size.x, 0); - uv = a_uv + vec2(u_textile.x * cycles.x, 0); + corner = a_pos + vec2(size.x, 0); + uv = a_uv + vec2(u_textile.x, 0); } else if (vertex_index == 2 || vertex_index == 4) { // "bottom left" aka "p3" - corner = a_pos + vec2(0, a_size.y); - uv = a_uv + vec2(0, u_textile.y * cycles.y); + corner = a_pos + vec2(0, size.y); + uv = a_uv + vec2(0, u_textile.y); } else { // "bottom right" aka "p4" - corner = a_pos + a_size; - uv = a_uv + u_textile * cycles; + corner = a_pos + size; + uv = a_uv + u_textile; } 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 float u_fade; + uniform int u_solid; layout(location = 0) out vec4 FragColor; void main() { - vec4 text = texture(u_texture, v_uv); - text.a = min(min(text.a, v_color.a), u_fade); - FragColor = vec4(text.rgb * text.a + v_color.rgb, 1.0); + if (u_solid != 0) { + FragColor = vec4(v_color.rgb * v_color.a, v_color.a); + } 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.uniform2f(program.locations['u_tile'], config.w, config.h); 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_size']); @@ -193,9 +208,15 @@ function draw(ts, animation) { gl.vertexAttribDivisor(program.locations['a_color'], 1); gl.vertexAttribDivisor(program.locations['a_uv'], 1); - gl.bindTexture(gl.TEXTURE_2D, textures['raster']); 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_size'], 0); gl.vertexAttribDivisor(program.locations['a_color'], 0); @@ -278,8 +299,12 @@ function init_webgl() { textures = { '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); 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.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) => { // https://www.khronos.org/webgl/wiki/HandlingHighDPI const entry = entries[0];