An upright piece came out as two solid halves instead of stripes. The guard that steps a board's ruling down asked only that the block span two cells, which is enough to keep it from going all ink or all paper -- the bug it was written for -- and nowhere near enough for the pattern to read. A screen's shape lives in its period: eight cells make one, and a block spanning less than that shows one or two arbitrary bands of a pattern rather than the pattern. It now asks for a period and a half. The other half was units. fitRuling was handed layout units while cell sizes are in buffer pixels, so it compared two different spaces and permitted whatever the density factor happened to be. Callers now pass buffer pixels. At DENSITY 1 this clamps a playing board to MEDIUM, which is what it could always actually carry. The coarse end of the ladder was never viable there; the density is what makes it so.
- commit
- faedf3dfb3a666ce6855383bef5a718029932425
- parent
- cede1751399e6ef53b3b514cc324c5c8a237441b
- author
- Dami <dami.etoile@gmail.com>
| M | mockup/ | 9 | ++++--- |
| M | mockup/ | 35 | +++++++++++++++++------------- |
| M | mockup/ | 2 | +- |
@@ -740,9 +740,10 @@ export function renderFrame() {
740740 // screen painters and need the same style the frame-level threshold will use.741741 const combo = resolveCombo();742742 curShading = combo.shading;743- // Stepped down to what the smallest piece on this board can carry. One744- // ruling for the whole board, taken from its cell.745- curRuling = fitRuling(combo.ruling, LY.cell || 16);743+ // Stepped down to what the smallest piece on this board can carry: one744+ // ruling for the whole board, measured in the buffer pixels the screen is745+ // actually cut in, against a 1x1's fill less its gap and outline.746+ curRuling = fitRuling(combo.ruling, dpx((LY.cell || 16) - 6));746747 curTile = GROUND_TILES[combo.backdrop] || GROUND_TILES.lattice;747748 curDot32 = pack(combo.ground.dot);748749 curField32 = pack(combo.ground.field);@@ -941,7 +942,7 @@ function drawAtlas(c) {
941942 const look = lookFor(fam.id, rec.rung);942943 drawGridInto(c, fam.board, grid, bx, by, mini, {943944 gap: 1, drop: 1, shadow: false,944- shading: look.shading, ruling: fitRuling(look.ruling, mini),945+ shading: look.shading, ruling: fitRuling(look.ruling, dpx(mini - 2)),945946 });946947 947948 const tx = G.tx;@@ -194,30 +194,35 @@ export function effectiveRuling(pattern, ruling) {
194194 return p && p.ruled && RULINGS[ruling] ? ruling : 'fine';195195 }196196 197-/* The one thing true coverage cannot rescue.197+/* A screen coarser than the thing it is printed on stops being a screen.198198 *199- * Making the inked area proportional fixes an unrepresentative slice of the200- * screen, because there is still a slice to choose within. It cannot do201- * anything at all when the block lands inside a *single* cell: one cell has one202- * threshold, one threshold has two outcomes, and neither of them is a quarter.203- * Measured, that is exactly where the remaining failures were -- a coarse screen204- * on a 6px preview piece came out solid, which is the same disappearance as205- * before wearing the other colour.199+ * Proportional coverage fixes an unrepresentative *slice* of a screen, because200+ * there is still a slice to choose within. It cannot do anything when there is201+ * barely a slice at all, and the threshold for "barely" is higher than it first202+ * looks. Two cells is enough to guarantee the block is neither all ink nor all203+ * paper -- which is what this once asked for, and it was not enough. A screen's204+ * shape lives in its whole period: eight cells make one, and a block spanning205+ * less than that does not show a pattern, it shows one or two arbitrary bands206+ * of it. A line screen makes that plainest -- an upright piece came out as two207+ * solid halves rather than as stripes -- but it is true of all of them.206208 *207- * So a board steps its ruling down until the smallest piece on it spans at208- * least two cells. Two is the whole requirement: with two thresholds present209- * there is always a cut that is neither all nor nothing, and proportional210- * coverage takes care of the rest.209+ * So the requirement is a period and a half, not two cells. That is the point210+ * at which the pattern repeats visibly enough to read as a pattern rather than211+ * as a coincidence.212+ *213+ * `fillPx` is in *buffer* pixels, because that is the space screens are214+ * measured in. Passing layout units instead was the other half of the same bug:215+ * the guard was comparing a cell size in real pixels against a length in216+ * layout ones, and quietly permitted whatever the density factor happened to be.211217 *212218 * Taken from the board's cell rather than from each sprite, so every piece is213219 * printed at one ruling. Choosing per piece would have let a 1x1 and the 2x2214220 * beside it come out at different frequencies, which is the one thing a press215221 * genuinely never does.216222 */217-export function fitRuling(ruling, cellPx) {218- const fill = cellPx - 6; // a 1x1's fill, less gap and outline223+export function fitRuling(ruling, fillPx) {219224 let out = ruling;220- while (RULINGS[out] && RULINGS[out].cell * 2 > fill) {225+ while (RULINGS[out] && RULINGS[out].cell * 12 > fillPx) { // 8 cells x 1.5221226 const i = RULING_NAMES.indexOf(out);222227 if (i <= 0) return 'fine';223228 out = RULING_NAMES[i - 1];