diff --git a/static/brush-box.js b/static/brush-box.js index bee6be6..78baefb 100644 --- a/static/brush-box.js +++ b/static/brush-box.js @@ -3,6 +3,7 @@ import { Haku } from "rkgk/haku.js"; import { randomId } from "rkgk/random.js"; import { SaveData } from "rkgk/framework.js"; import { ContextMenu, globalContextMenuSpace } from "rkgk/context-menu.js"; +import { BrushRenderer } from "rkgk/brush-renderer.js"; export const builtInPresets = [ { @@ -15,7 +16,7 @@ color: #000 thickness: 8 withDotter \\d -> - stroke thickness color (line d.From d.To) + stroke thickness color d.From d.To `.trim(), }, @@ -27,7 +28,7 @@ color: #000 thickness: 48 withDotter \\d -> - stroke thickness color (line d.From d.To) + stroke thickness color d.From d.To `.trim(), }, @@ -43,7 +44,7 @@ duty: 0.5 withDotter \\d -> visible? = d.Num |mod length < length * duty if (visible?) - stroke thickness color (line d.From d.To) + stroke thickness color d.From d.To else () `.trim(), @@ -57,7 +58,7 @@ color: #0003 thickness: 6 withDotter \\d -> - stroke thickness color (line d.From d.To) + stroke thickness color d.From d.To `.trim(), }, @@ -75,7 +76,7 @@ withDotter \\d -> a = sin (d.Num * wavelength / pi) + 1 / 2 range = maxThickness - minThickness thickness = a * range + minThickness - stroke thickness color (line d.From d.To) + stroke thickness color d.From d.To `.trim(), }, @@ -104,7 +105,7 @@ withDotter \\d -> clockwise = norm (perpClockwise d.To-d.From) * vec a a from = d.From + clockwise to = d.To + clockwise - stroke thickness color (line from to) + stroke thickness color from to `.trim(), }, @@ -125,7 +126,7 @@ withDotter \\d -> g = colorCurve (d.Num * l + pi/3) b = colorCurve (d.Num * l + 2*pi/3) color = rgba r g b 1 - stroke thickness color (line d.From d.To) + stroke thickness color d.From d.To `.trim(), }, @@ -134,7 +135,8 @@ withDotter \\d -> function presetButton(info) { let button = document.createElement("button"); - let preview = button.appendChild(new BrushPreview(56, 56)); + let preview = button.appendChild(document.createElement("div")); + preview.classList.add("preview"); let label = button.appendChild(document.createElement("p")); label.classList.add("label"); label.innerText = info.name; @@ -172,6 +174,14 @@ export class BrushBox extends HTMLElement { initialize(wallLimits) { this.haku = new Haku(wallLimits); + + this.brushesCanvas = this.appendChild(document.createElement("canvas")); + this.gl = this.brushesCanvas.getContext("webgl2"); + let canvasResizeObserver = new ResizeObserver(() => this.renderBrushes()); + canvasResizeObserver.observe(this); + + this.brushRenderer = new BrushRenderer(this.gl, this.canvasSource()); + this.renderBrushes(); } @@ -290,10 +300,61 @@ export class BrushBox extends HTMLElement { if (this.currentPresetId != null) this.setCurrentBrush(this.currentPresetId); } + canvasSource() { + let brushBox = this; + return { + useCanvas(gl, i) { + let brush = brushBox.brushes[i]; + + let canvasRect = brushBox.brushesCanvas.getBoundingClientRect(); + let previewRect = brush.presetButton.preview.getBoundingClientRect(); + let viewport = { + x: previewRect.x - canvasRect.x, + y: canvasRect.bottom - previewRect.bottom, + width: previewRect.width, + height: previewRect.height, + }; + + gl.enable(gl.SCISSOR_TEST); + gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height); + gl.scissor(viewport.x, viewport.y, viewport.width, viewport.height); + + return viewport; + }, + + resetCanvas(gl) {}, + }; + } + async renderBrushes() { - for (let brush of this.brushes) { + let gl = this.gl; + + this.brushesCanvas.width = this.brushesCanvas.clientWidth; + this.brushesCanvas.height = this.brushesContainer.scrollHeight; + + gl.clearColor(0, 0, 0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + + for (let i = 0; i < this.brushes.length; ++i) { + let brush = this.brushes[i]; + let previewRect = brush.presetButton.preview.getBoundingClientRect(); + this.haku.setBrush(brush.preset.code); - await brush.presetButton.preview.renderBrush(this.haku); + await this.haku.evalBrush({ + runDotter: async () => { + return { + fromX: previewRect.width / 2, + fromY: previewRect.height / 2, + toX: previewRect.width / 2, + toY: previewRect.height / 2, + num: 0, + }; + }, + + runScribble: async (renderToCanvas) => { + renderToCanvas(this.brushRenderer, i, 0, 0); + }, + }); } } diff --git a/static/index.css b/static/index.css index b9bc61f..6bedf33 100644 --- a/static/index.css +++ b/static/index.css @@ -283,6 +283,8 @@ rkgk-reticle-cursor { rkgk-brush-box { --button-size: 56px; + position: relative; + height: var(--height); padding: 12px; @@ -316,7 +318,7 @@ rkgk-brush-box { border-color: var(--color-brand-blue); } - & > rkgk-brush-preview { + & > .preview { width: var(--button-size); aspect-ratio: 1 / 1; background: none; @@ -352,6 +354,18 @@ rkgk-brush-box { display: flex; } } + + & > canvas { + position: absolute; + left: 0; + top: 0; + width: 100%; + margin: 12px; + + pointer-events: none; + + image-rendering: pixelated; + } } /* Code editor */