make the brush box work under the new GPU renderer

the brush preview will need separate treatment, but it shouldn't be too difficult
This commit is contained in:
りき萌 2025-09-09 22:07:26 +02:00
parent 63d5c04a0d
commit 2810fe248f
2 changed files with 86 additions and 11 deletions

View file

@ -3,6 +3,7 @@ import { Haku } from "rkgk/haku.js";
import { randomId } from "rkgk/random.js"; import { randomId } from "rkgk/random.js";
import { SaveData } from "rkgk/framework.js"; import { SaveData } from "rkgk/framework.js";
import { ContextMenu, globalContextMenuSpace } from "rkgk/context-menu.js"; import { ContextMenu, globalContextMenuSpace } from "rkgk/context-menu.js";
import { BrushRenderer } from "rkgk/brush-renderer.js";
export const builtInPresets = [ export const builtInPresets = [
{ {
@ -15,7 +16,7 @@ color: #000
thickness: 8 thickness: 8
withDotter \\d -> withDotter \\d ->
stroke thickness color (line d.From d.To) stroke thickness color d.From d.To
`.trim(), `.trim(),
}, },
@ -27,7 +28,7 @@ color: #000
thickness: 48 thickness: 48
withDotter \\d -> withDotter \\d ->
stroke thickness color (line d.From d.To) stroke thickness color d.From d.To
`.trim(), `.trim(),
}, },
@ -43,7 +44,7 @@ duty: 0.5
withDotter \\d -> withDotter \\d ->
visible? = d.Num |mod length < length * duty visible? = d.Num |mod length < length * duty
if (visible?) if (visible?)
stroke thickness color (line d.From d.To) stroke thickness color d.From d.To
else else
() ()
`.trim(), `.trim(),
@ -57,7 +58,7 @@ color: #0003
thickness: 6 thickness: 6
withDotter \\d -> withDotter \\d ->
stroke thickness color (line d.From d.To) stroke thickness color d.From d.To
`.trim(), `.trim(),
}, },
@ -75,7 +76,7 @@ withDotter \\d ->
a = sin (d.Num * wavelength / pi) + 1 / 2 a = sin (d.Num * wavelength / pi) + 1 / 2
range = maxThickness - minThickness range = maxThickness - minThickness
thickness = a * range + minThickness thickness = a * range + minThickness
stroke thickness color (line d.From d.To) stroke thickness color d.From d.To
`.trim(), `.trim(),
}, },
@ -104,7 +105,7 @@ withDotter \\d ->
clockwise = norm (perpClockwise d.To-d.From) * vec a a clockwise = norm (perpClockwise d.To-d.From) * vec a a
from = d.From + clockwise from = d.From + clockwise
to = d.To + clockwise to = d.To + clockwise
stroke thickness color (line from to) stroke thickness color from to
`.trim(), `.trim(),
}, },
@ -125,7 +126,7 @@ withDotter \\d ->
g = colorCurve (d.Num * l + pi/3) g = colorCurve (d.Num * l + pi/3)
b = colorCurve (d.Num * l + 2*pi/3) b = colorCurve (d.Num * l + 2*pi/3)
color = rgba r g b 1 color = rgba r g b 1
stroke thickness color (line d.From d.To) stroke thickness color d.From d.To
`.trim(), `.trim(),
}, },
@ -134,7 +135,8 @@ withDotter \\d ->
function presetButton(info) { function presetButton(info) {
let button = document.createElement("button"); 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")); let label = button.appendChild(document.createElement("p"));
label.classList.add("label"); label.classList.add("label");
label.innerText = info.name; label.innerText = info.name;
@ -172,6 +174,14 @@ export class BrushBox extends HTMLElement {
initialize(wallLimits) { initialize(wallLimits) {
this.haku = new Haku(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(); this.renderBrushes();
} }
@ -290,10 +300,61 @@ export class BrushBox extends HTMLElement {
if (this.currentPresetId != null) this.setCurrentBrush(this.currentPresetId); 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() { 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); 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);
},
});
} }
} }

View file

@ -283,6 +283,8 @@ rkgk-reticle-cursor {
rkgk-brush-box { rkgk-brush-box {
--button-size: 56px; --button-size: 56px;
position: relative;
height: var(--height); height: var(--height);
padding: 12px; padding: 12px;
@ -316,7 +318,7 @@ rkgk-brush-box {
border-color: var(--color-brand-blue); border-color: var(--color-brand-blue);
} }
& > rkgk-brush-preview { & > .preview {
width: var(--button-size); width: var(--button-size);
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
background: none; background: none;
@ -352,6 +354,18 @@ rkgk-brush-box {
display: flex; display: flex;
} }
} }
& > canvas {
position: absolute;
left: 0;
top: 0;
width: 100%;
margin: 12px;
pointer-events: none;
image-rendering: pixelated;
}
} }
/* Code editor */ /* Code editor */