127 lines
4.4 KiB
C
127 lines
4.4 KiB
C
// Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License.
|
|
// See LICENSE.md for license information.
|
|
// SPDX-License-Identifier: MIT
|
|
//
|
|
// keysCells.c - read which of KEYS's named-key cells are lit off a
|
|
// screenshot.
|
|
//
|
|
// keysCells PNG [--at X,Y] [--scale S]
|
|
//
|
|
// KEYS (examples/keys) draws a cell for each named key, lit (colour 2,
|
|
// green) while jlKeyDown says it is down and dark grey (colour 1)
|
|
// otherwise. This reads the cells of its fourth row that a port gives a
|
|
// second physical key for -- Return, Ctrl, Alt, Up, Down, Left, and Right
|
|
// -- at the middle of each, and prints one digit a cell, in that order: 1
|
|
// lit, 0 not, ? neither colour.
|
|
//
|
|
// --at: where the stage's top left is in the screenshot (default 0,0).
|
|
// --scale: screen pixels a stage pixel (default 1). A point off the
|
|
// screenshot is fatal (exit 1); a bad command line exits 2.
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "gateArg.h"
|
|
#include "gateImage.h"
|
|
#include "toolFile.h"
|
|
|
|
#define TOOL_NAME "keysCells"
|
|
// examples/keys: CELL_W x CELL_H cells GAP apart from (MARGIN_X,
|
|
// MARGIN_Y), the named keys in row 4 at these columns.
|
|
#define CELL_W 28
|
|
#define CELL_H 26
|
|
#define GAP 4
|
|
#define MARGIN_X 2
|
|
#define MARGIN_Y 2
|
|
#define ROW 4
|
|
#define COLUMN_COUNT 7u
|
|
// KEYS's colours 1 and 2, and how near a pixel must be: a 15- or 16-bit
|
|
// screen is off by at most 8 a gun.
|
|
#define UNLIT_INDEX 1u
|
|
#define LIT_INDEX 2u
|
|
#define MAX_DIST (3u * 9u * 9u)
|
|
|
|
|
|
// Return, Ctrl, Alt, Up, Down, Left, Right.
|
|
static const long kColumns[COLUMN_COUNT] = { 2, 3, 4, 5, 6, 7, 8 };
|
|
|
|
static const char *const kUsage[] = {
|
|
"keysCells - read which of KEYS's named-key cells are lit off a screenshot.",
|
|
"",
|
|
"KEYS (examples/keys) draws a cell for each named key, lit (colour 2, green)",
|
|
"while jlKeyDown says it is down and dark grey (colour 1) otherwise. This",
|
|
"reads the cells of its fourth row that a port gives a second physical key",
|
|
"for -- Return, Ctrl, Alt, Up, Down, Left, and Right -- at the middle of",
|
|
"each, and prints one digit a cell, in that order: 1 lit, 0 not, ? neither",
|
|
"colour.",
|
|
"",
|
|
" keysCells PNG [--at X,Y] [--scale S]",
|
|
"",
|
|
"--at: where the stage's top left is in the screenshot (default 0,0).",
|
|
"--scale: screen pixels a stage pixel (default 1)."
|
|
};
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
GateImageT img;
|
|
const char *png;
|
|
const uint8_t *pixel;
|
|
uint16_t words[GATE_KEYS_COLOURS];
|
|
uint8_t lit[GATE_RGB_BYTES];
|
|
uint8_t unlit[GATE_RGB_BYTES];
|
|
char digits[COLUMN_COUNT + 1u];
|
|
long atX;
|
|
long atY;
|
|
long scale;
|
|
long x;
|
|
long y;
|
|
uint32_t i;
|
|
int arg;
|
|
|
|
toolFileName(TOOL_NAME);
|
|
png = NULL;
|
|
atX = 0;
|
|
atY = 0;
|
|
scale = 1;
|
|
for (arg = 1; arg < argc; arg++) {
|
|
if (strcmp(argv[arg], "--at") == 0 && arg + 1 < argc) {
|
|
gateArgPair("at", argv[++arg], ',', &atX, &atY);
|
|
} else if (strcmp(argv[arg], "--scale") == 0 && arg + 1 < argc) {
|
|
scale = gateArgLong("scale", argv[++arg]);
|
|
if (scale < 1) {
|
|
gateArgBad("scale", argv[arg]);
|
|
}
|
|
} else if (argv[arg][0] == '-' || png != NULL) {
|
|
return gateUsage(kUsage, GATE_COUNT_OF(kUsage));
|
|
} else {
|
|
png = argv[arg];
|
|
}
|
|
}
|
|
if (png == NULL) {
|
|
return gateUsage(kUsage, GATE_COUNT_OF(kUsage));
|
|
}
|
|
gateImageLoad(png, &img);
|
|
gateKeysPalette(words);
|
|
gateRgb12(words[LIT_INDEX], lit);
|
|
gateRgb12(words[UNLIT_INDEX], unlit);
|
|
// Each cell's middle, on the screenshot.
|
|
y = atY + (MARGIN_Y + ROW * (CELL_H + GAP) + CELL_H / 2) * scale;
|
|
for (i = 0; i < COLUMN_COUNT; i++) {
|
|
x = atX + (MARGIN_X + kColumns[i] * (CELL_W + GAP) + CELL_W / 2) * scale;
|
|
if (!gateImageHas(&img, x, y)) {
|
|
toolFail("cell %u's middle, %ld,%ld, is off the %ux%u screenshot", (unsigned)i, x, y, (unsigned)img.width, (unsigned)img.height);
|
|
}
|
|
pixel = gateImagePixel(&img, (uint32_t)x, (uint32_t)y);
|
|
if (gateDistance(pixel, lit) <= MAX_DIST) {
|
|
digits[i] = '1';
|
|
} else if (gateDistance(pixel, unlit) <= MAX_DIST) {
|
|
digits[i] = '0';
|
|
} else {
|
|
digits[i] = '?';
|
|
}
|
|
}
|
|
digits[COLUMN_COUNT] = '\0';
|
|
printf("%s\n", digits);
|
|
gateImageFree(&img);
|
|
return 0;
|
|
}
|