Squash Odysseus development history

This commit is contained in:
pewdiepie-archdaemon
2026-09-11 06:04:19 +00:00
parent e5c99a5eee
commit 6ee6502010
2050 changed files with 538359 additions and 57745 deletions
+10 -74
View File
@@ -14,11 +14,15 @@
* fitZoom: () => void,
* showCanvasLoading: (label: string) => void,
* hideCanvasLoading: () => void,
* renderLayerPanel: () => void,
* }} deps
*/
import { state } from './state.js';
import { flipDocument, rotateDocument } from './document-geometry.js';
export function createCanvasTransforms({ saveState, composite, fitZoom, showCanvasLoading, hideCanvasLoading }) {
export function createCanvasTransforms({
saveState, composite, fitZoom, showCanvasLoading, hideCanvasLoading, renderLayerPanel,
}) {
return {
/**
* Rotate the entire document by `deg` (90 / 180 / 270). 90 and 270
@@ -34,61 +38,14 @@ export function createCanvasTransforms({ saveState, composite, fitZoom, showCanv
if (!state.layers.length) return;
saveState(`Rotate ${deg}°`);
showCanvasLoading('Rotating…');
const oldW = state.imgWidth, oldH = state.imgHeight;
const swap = (deg === 90 || deg === 270);
const newW = swap ? oldH : oldW;
const newH = swap ? oldW : oldH;
const rad = (deg * Math.PI) / 180;
const cos = Math.cos(rad), sin = Math.sin(rad);
requestAnimationFrame(() => {
try {
for (const layer of state.layers) {
const lw = layer.canvas.width, lh = layer.canvas.height;
const off = state.layerOffsets.get(layer.id) || { x: 0, y: 0 };
// Layer centre in old image coords.
const cx = off.x + lw / 2;
const cy = off.y + lh / 2;
// Rotate the centre around the old image centre and
// translate so the new image centre lands at (newW/2, newH/2).
const dx = cx - oldW / 2;
const dy = cy - oldH / 2;
const nx = dx * cos - dy * sin + newW / 2;
const ny = dx * sin + dy * cos + newH / 2;
// New per-layer dims: swap when 90/270.
const newLw = swap ? lh : lw;
const newLh = swap ? lw : lh;
const tmp = document.createElement('canvas');
tmp.width = newLw; tmp.height = newLh;
const tctx = tmp.getContext('2d');
tctx.translate(newLw / 2, newLh / 2);
tctx.rotate(rad);
tctx.drawImage(layer.canvas, -lw / 2, -lh / 2);
layer.canvas.width = newLw;
layer.canvas.height = newLh;
layer.ctx.drawImage(tmp, 0, 0);
// The adjustment-render caches are keyed only by the adjustment
// signature, which rotation doesn't change — so composite would draw
// the STALE pre-rotation cache (the "had to click twice" bug). Drop
// them so the next composite re-renders from the rotated canvas.
layer._adjCacheKey = null;
layer._adjFinalKey = null;
state.layerOffsets.set(layer.id, {
x: Math.round(nx - newLw / 2),
y: Math.round(ny - newLh / 2),
});
}
state.imgWidth = newW;
state.imgHeight = newH;
state.mainCanvas.width = newW;
state.mainCanvas.height = newH;
if (state.maskCanvas) {
state.maskCanvas.width = newW;
state.maskCanvas.height = newH;
}
const result = rotateDocument(state, deg);
const sizeLabel = document.getElementById('ge-canvas-size');
if (sizeLabel) sizeLabel.textContent = `${newW}×${newH}`;
if (sizeLabel && result) sizeLabel.textContent = `${result.width}×${result.height}`;
fitZoom();
composite();
renderLayerPanel?.();
} finally {
hideCanvasLoading();
}
@@ -103,30 +60,9 @@ export function createCanvasTransforms({ saveState, composite, fitZoom, showCanv
flipAll(axis) {
if (!state.layers.length) return;
saveState(axis === 'h' ? 'Flip horizontal' : 'Flip vertical');
for (const layer of state.layers) {
const lw = layer.canvas.width, lh = layer.canvas.height;
const tmp = document.createElement('canvas');
tmp.width = lw; tmp.height = lh;
const tctx = tmp.getContext('2d');
tctx.save();
if (axis === 'h') { tctx.translate(lw, 0); tctx.scale(-1, 1); }
else { tctx.translate(0, lh); tctx.scale(1, -1); }
tctx.drawImage(layer.canvas, 0, 0);
tctx.restore();
layer.ctx.clearRect(0, 0, lw, lh);
layer.ctx.drawImage(tmp, 0, 0);
// Invalidate the adjustment-render caches (keyed by adjustment sig only)
// so composite redraws from the flipped canvas, not a stale cache.
layer._adjCacheKey = null;
layer._adjFinalKey = null;
const off = state.layerOffsets.get(layer.id) || { x: 0, y: 0 };
if (axis === 'h') {
state.layerOffsets.set(layer.id, { x: state.imgWidth - off.x - lw, y: off.y });
} else {
state.layerOffsets.set(layer.id, { x: off.x, y: state.imgHeight - off.y - lh });
}
}
flipDocument(state, axis);
composite();
renderLayerPanel?.();
},
};
}