/** * @fileoverview * 调试 MG 渲染器的测试脚本 * * @author SteveXMH */ import GUI from "lil-gui"; import Stats from "stats.js"; import { MeshGradientRenderer } from "./bg-render"; const debugValues = { controlPointSize: 4, subdivideDepth: 15, wireFrame: false, }; const canvas = document.getElementById("bg")! as HTMLCanvasElement; const mgRenderer = new MeshGradientRenderer(canvas); // mgRenderer.setAlbum("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAADUExURf///6fEG8gAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAKSURBVBjTY2AAAAACAAGYY2zXAAAAAElFTkSuQmCC"); mgRenderer.setManualControl(true); mgRenderer.setFPS(Number.POSITIVE_INFINITY); function updateControlPointDraggers() { for (const el of document.querySelectorAll(".dragger")) { const x = Number.parseInt(el.getAttribute("x") ?? ""); const y = Number.parseInt(el.getAttribute("y") ?? ""); const point = mgRenderer.getControlPoint(x, y); if (point === undefined) return; (el as HTMLElement).style.left = `${(point.location.x + 1) * 50}%`; (el as HTMLElement).style.top = `${(1 - point.location.y) * 50}%`; } } let draggerGui: GUI | undefined; function setActiveDragger(x: number, y: number) { if (draggerGui) { draggerGui.destroy(); draggerGui = undefined; } const point = mgRenderer.getControlPoint(x, y); if (point) { draggerGui = gui.addFolder(`控制点 (${x}, ${y})`); const obj = { uAngle: point.uRot, vAngle: point.vRot, uScale: point.uScale, vScale: point.vScale, }; draggerGui .add(obj, "uAngle", -180, 180) .name("横向扭曲角度") .onChange((v: number) => { point.uRot = (v * Math.PI) / 180; updateResult(); }); draggerGui .add(obj, "vAngle", -180, 180) .name("纵向扭曲角度") .onChange((v: number) => { point.vRot = (v * Math.PI) / 180; updateResult(); }); draggerGui .add(obj, "uScale", 0.1, 10) .name("横向缩放") .onChange((v: number) => { point.uScale = v; updateResult(); }); draggerGui .add(obj, "vScale", 0.1, 10) .name("纵向缩放") .onChange((v: number) => { point.vScale = v; updateResult(); }); } } window.addEventListener("resize", updateControlPointDraggers); const resultTextArea = document.getElementById( "result", )! as HTMLTextAreaElement; resultTextArea.value = "// 控制点的设置代码将会在这里显示"; function updateResult() { const result = [ `preset(${debugValues.controlPointSize}, ${debugValues.controlPointSize}, [`, ]; for (let y = 0; y < debugValues.controlPointSize; y++) { for (let x = 0; x < debugValues.controlPointSize; x++) { const point = mgRenderer.getControlPoint(x, y); if (point === undefined) continue; result.push( ` p(${x}, ${y}, ${point.location.x}, ${point.location.y}, ${point.uRot}, ${point.vRot}, ${point.uScale}, ${point.vScale}),`, ); } } result.push("]),"); resultTextArea.value = result.join("\n"); } function resizeControlPoint() { document .querySelectorAll(".dragger") .forEach((el) => el.parentElement?.removeChild(el)); mgRenderer.resizeControlPoints( debugValues.controlPointSize, debugValues.controlPointSize, ); mgRenderer.resetSubdivition(debugValues.subdivideDepth); for (let y = 0; y < debugValues.controlPointSize; y++) { for (let x = 0; x < debugValues.controlPointSize; x++) { const point = mgRenderer.getControlPoint(x, y); if (point === undefined) continue; const dragger = document.createElement("div"); const draggerInput = document.createElement("input"); draggerInput.type = "color"; draggerInput.style.position = "absolute"; draggerInput.style.visibility = "hidden"; dragger.appendChild(draggerInput); dragger.setAttribute("x", `${x}`); dragger.setAttribute("y", `${y}`); dragger.className = "dragger"; dragger.style.left = `${(x * 100) / (debugValues.controlPointSize - 1)}%`; dragger.style.top = `${ ((debugValues.controlPointSize - y - 1) * 100) / (debugValues.controlPointSize - 1) }%`; draggerInput.addEventListener("input", () => { // mgRenderer.getControlPoint(x, y).color = dragger.value; const c = draggerInput.value; console.log(c); dragger.style.backgroundColor = c; const color = c.match(/#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i); if (color) { point.color.r = Number.parseInt(color[1], 16) / 255; point.color.g = Number.parseInt(color[2], 16) / 255; point.color.b = Number.parseInt(color[3], 16) / 255; dragger.setAttribute("r", `${point.color.r}`); dragger.setAttribute("g", `${point.color.g}`); dragger.setAttribute("b", `${point.color.b}`); updateResult(); } }); let dragging = false; dragger.addEventListener("mousedown", (evt) => { evt.stopPropagation(); function onMouseMove(evt: MouseEvent) { dragger.style.left = `${Math.min( window.innerWidth, Math.max(0, evt.clientX), )}px`; dragger.style.top = `${Math.min( window.innerHeight, Math.max(0, evt.clientY), )}px`; if (point) { point.location.x = Math.max( -1, Math.min(1, (evt.clientX / window.innerWidth) * 2 - 1), ); point.location.y = Math.max( -1, Math.min(1, -((evt.clientY / window.innerHeight) * 2 - 1)), ); } dragging = true; updateResult(); evt.stopPropagation(); } function onMouseUp(evt: MouseEvent) { if (dragging) { dragging = false; } else if (dragger.classList.contains("active")) { draggerInput.click(); } else { for (const el of document.querySelectorAll(".dragger.active")) { el.classList.remove("active"); } dragger.classList.add("active"); setActiveDragger(x, y); } window.removeEventListener("mousemove", onMouseMove); window.removeEventListener("mouseup", onMouseUp); evt.stopPropagation(); } window.addEventListener("mousemove", onMouseMove); window.addEventListener("mouseup", onMouseUp); }); document.body.appendChild(dragger); } } } function subdivide() { mgRenderer.resetSubdivition(debugValues.subdivideDepth); } mgRenderer.setAlbum("bigsur.png").then(() => { resizeControlPoint(); subdivide(); }); const gui = new GUI(); gui.close(); gui.title("MG Renderer 调试页面"); gui .add(debugValues, "controlPointSize", 3, 10, 1) .name("控制点矩阵大小") .onFinishChange(resizeControlPoint); gui .add(debugValues, "subdivideDepth", 2, 50, 1) .name("细分深度") .onChange(subdivide); gui .add(debugValues, "wireFrame") .name("线框模式") .onChange((v: boolean) => mgRenderer.setWireFrame(v)); const stats = new Stats(); stats.showPanel(0); stats.dom.style.left = "50px"; document.body.appendChild(stats.dom); const frame = () => { stats.end(); stats.begin(); requestAnimationFrame(frame); }; requestAnimationFrame(frame);