diff options
Diffstat (limited to 'image.c')
-rw-r--r-- | image.c | 169 |
1 files changed, 102 insertions, 67 deletions
diff --git a/image.c b/image.c index ef583e9..d67706f 100644 --- a/image.c +++ b/image.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <string.h> #include <sys/mman.h> +#include <sys/stat.h> #include <sysexits.h> #include <unistd.h> #include <zlib.h> @@ -47,6 +48,64 @@ static const uint8_t Palette[16][3] = { { 0xFF, 0xFF, 0xFF }, }; +static struct { + uint32_t magic; + uint32_t version; + uint32_t size; + uint32_t flags; + struct { + uint32_t len; + uint32_t size; + uint32_t height; + uint32_t width; + } glyph; +} font; + +static uint8_t *glyphs; + +static void fontLoad(const char *path) { + FILE *file = fopen(path, "r"); + if (!file) err(EX_NOINPUT, "%s", path); + + size_t len = fread(&font, sizeof(font), 1, file); + if (ferror(file)) err(EX_IOERR, "%s", path); + if (len < 1) errx(EX_DATAERR, "%s: truncated header", path); + + if (font.magic != 0x864AB572 || font.size != sizeof(font)) { + errx(EX_DATAERR, "%s: invalid header", path); + } + + glyphs = calloc(font.glyph.len, font.glyph.size); + if (!glyphs) err(EX_OSERR, "calloc"); + + len = fread(glyphs, font.glyph.size, font.glyph.len, file); + if (ferror(file)) err(EX_IOERR, "%s", path); + if (len < font.glyph.len) errx(EX_DATAERR, "%s: truncated glyphs", path); + fclose(file); +} + +static struct Tile (*tiles)[TileRows][TileCols]; + +static void tilesMap(const char *path) { + int fd = open(path, O_RDONLY); + if (fd < 0) err(EX_NOINPUT, "%s", path); + + struct stat stat; + int error = fstat(fd, &stat); + if (error) err(EX_IOERR, "%s", path); + + if ((size_t)stat.st_size < TilesSize) { + errx(EX_DATAERR, "%s: truncated tiles", path); + } + + tiles = mmap(NULL, TilesSize, PROT_READ, MAP_SHARED, fd, 0); + if (tiles == MAP_FAILED) err(EX_OSERR, "mmap"); + close(fd); + + error = madvise(tiles, TilesSize, MADV_RANDOM); + if (error) err(EX_OSERR, "madvise"); +} + static uint32_t crc; static void pngWrite(const void *ptr, size_t size) { fwrite(ptr, size, 1, stdout); @@ -63,64 +122,12 @@ static void pngChunk(char type[static 4], uint32_t size) { pngWrite(type, 4); } -int main(int argc, char *argv[]) { - const char *fontPath = "default8x16.psfu"; - const char *dataPath = "torus.dat"; - uint32_t tileX = TileInitX; - uint32_t tileY = TileInitY; - - int opt; - while (0 < (opt = getopt(argc, argv, "d:f:x:y:"))) { - switch (opt) { - break; case 'd': dataPath = optarg; - break; case 'f': fontPath = optarg; - break; case 'x': tileX = strtoul(optarg, NULL, 0) % TileCols; - break; case 'y': tileY = strtoul(optarg, NULL, 0) % TileRows; - break; default: return EX_USAGE; - } - } - - FILE *file = fopen(fontPath, "r"); - if (!file) err(EX_NOINPUT, "%s", fontPath); - - struct { - uint32_t magic; - uint32_t version; - uint32_t size; - uint32_t flags; - struct { - uint32_t len; - uint32_t size; - uint32_t height; - uint32_t width; - } glyph; - } psf; - size_t len = fread(&psf, sizeof(psf), 1, file); - if (ferror(file)) err(EX_IOERR, "%s", fontPath); - if (len < 1) errx(EX_DATAERR, "%s: truncated header", fontPath); - - uint8_t glyphs[psf.glyph.len][psf.glyph.height][(psf.glyph.width + 7) / 8]; - len = fread(glyphs, psf.glyph.size, psf.glyph.len, file); - if (ferror(file)) err(EX_IOERR, "%s", fontPath); - if (len < 1) errx(EX_DATAERR, "%s: truncated glyphs", fontPath); - fclose(file); - - int fd = open(dataPath, O_RDONLY); - if (fd < 0) err(EX_NOINPUT, "%s", dataPath); - - struct Tile *tile = mmap( - NULL, sizeof(struct Tile), - PROT_READ, MAP_SHARED, - fd, sizeof(struct Tile) * (TileRows * tileY + tileX) - ); - if (tile == MAP_FAILED) err(EX_IOERR, "mmap"); - close(fd); +static void render(uint32_t tileX, uint32_t tileY) { + uint32_t width = CellCols * font.glyph.width; + uint32_t height = CellRows * font.glyph.height; pngWrite("\x89PNG\r\n\x1A\n", 8); - uint32_t width = CellCols * psf.glyph.width; - uint32_t height = CellRows * psf.glyph.height; - pngChunk("IHDR", 13); pngInt(width); pngInt(height); @@ -134,18 +141,23 @@ int main(int argc, char *argv[]) { uint8_t data[height][1 + width]; memset(data, 0, sizeof(data)); - for (uint32_t y = 0; y < CellRows; ++y) { - for (uint32_t x = 0; x < CellCols; ++x) { - uint8_t cell = tile->cells[y][x]; - uint8_t fg = tile->colors[y][x] & 0x0F; - uint8_t bg = tile->colors[y][x] >> 4; - - uint32_t row = psf.glyph.height * y; - uint32_t col = psf.glyph.width * x; - for (uint8_t gy = 0; gy < psf.glyph.height; ++gy) { - for (uint8_t gx = 0; gx < psf.glyph.width; ++gx) { - uint8_t bit = glyphs[cell][gy][gx / 8] >> (7 - gx % 8) & 1; - data[row + gy][1 + col + gx] = (bit ? fg : bg); + uint32_t widthBytes = (font.glyph.width + 7) / 8; + uint8_t (*bits)[font.glyph.len][font.glyph.height][widthBytes]; + bits = (void *)glyphs; + + struct Tile *tile = &(*tiles)[tileY][tileX]; + for (uint32_t cellY = 0; cellY < CellRows; ++cellY) { + for (uint32_t cellX = 0; cellX < CellCols; ++cellX) { + uint8_t cell = tile->cells[cellY][cellX]; + uint8_t fg = tile->colors[cellY][cellX] & 0x0F; + uint8_t bg = tile->colors[cellY][cellX] >> 4; + + uint32_t glyphX = font.glyph.width * cellX; + uint32_t glyphY = font.glyph.height * cellY; + for (uint32_t y = 0; y < font.glyph.height; ++y) { + for (uint32_t x = 0; x < font.glyph.width; ++x) { + uint8_t bit = (*bits)[cell][y][x / 8] >> (7 - x % 8) & 1; + data[glyphY + y][1 + glyphX + x] = (bit ? fg : bg); } } } @@ -162,6 +174,29 @@ int main(int argc, char *argv[]) { pngChunk("IEND", 0); pngInt(crc); +} + +int main(int argc, char *argv[]) { + const char *fontPath = "default8x16.psfu"; + const char *dataPath = "torus.dat"; + uint32_t tileX = TileInitX; + uint32_t tileY = TileInitY; + + int opt; + while (0 < (opt = getopt(argc, argv, "d:f:x:y:"))) { + switch (opt) { + break; case 'd': dataPath = optarg; + break; case 'f': fontPath = optarg; + break; case 'x': tileX = strtoul(optarg, NULL, 0) % TileCols; + break; case 'y': tileY = strtoul(optarg, NULL, 0) % TileRows; + break; default: return EX_USAGE; + } + } + + fontLoad(fontPath); + tilesMap(dataPath); + + render(tileX, tileY); return EX_OK; } |