No Description https://ascii.town
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

image.c 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /* Copyright (C) 2018 Curtis McEnroe <june@causal.agency>
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU Affero General Public License as published by
  5. * the Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <err.h>
  17. #include <fcntl.h>
  18. #include <stdint.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <sys/mman.h>
  23. #include <sys/stat.h>
  24. #include <sysexits.h>
  25. #include <unistd.h>
  26. #include "png.h"
  27. #include "torus.h"
  28. static const uint8_t Palette[16][3] = {
  29. { 0x00, 0x00, 0x00 },
  30. { 0xAA, 0x00, 0x00 },
  31. { 0x00, 0xAA, 0x00 },
  32. { 0xAA, 0x55, 0x00 },
  33. { 0x00, 0x00, 0xAA },
  34. { 0xAA, 0x00, 0xAA },
  35. { 0x00, 0xAA, 0xAA },
  36. { 0xAA, 0xAA, 0xAA },
  37. { 0x55, 0x55, 0x55 },
  38. { 0xFF, 0x55, 0x55 },
  39. { 0x55, 0xFF, 0x55 },
  40. { 0xFF, 0xFF, 0x55 },
  41. { 0x55, 0x55, 0xFF },
  42. { 0xFF, 0x55, 0xFF },
  43. { 0x55, 0xFF, 0xFF },
  44. { 0xFF, 0xFF, 0xFF },
  45. };
  46. static struct {
  47. uint32_t magic;
  48. uint32_t version;
  49. uint32_t size;
  50. uint32_t flags;
  51. struct {
  52. uint32_t len;
  53. uint32_t size;
  54. uint32_t height;
  55. uint32_t width;
  56. } glyph;
  57. } font;
  58. static uint8_t *glyphs;
  59. static void fontLoad(const char *path) {
  60. FILE *file = fopen(path, "r");
  61. if (!file) err(EX_NOINPUT, "%s", path);
  62. size_t len = fread(&font, sizeof(font), 1, file);
  63. if (ferror(file)) err(EX_IOERR, "%s", path);
  64. if (len < 1) errx(EX_DATAERR, "%s: truncated header", path);
  65. if (font.magic != 0x864AB572 || font.size != sizeof(font)) {
  66. errx(EX_DATAERR, "%s: invalid header", path);
  67. }
  68. glyphs = calloc(font.glyph.len, font.glyph.size);
  69. if (!glyphs) err(EX_OSERR, "calloc");
  70. len = fread(glyphs, font.glyph.size, font.glyph.len, file);
  71. if (ferror(file)) err(EX_IOERR, "%s", path);
  72. if (len < font.glyph.len) errx(EX_DATAERR, "%s: truncated glyphs", path);
  73. fclose(file);
  74. }
  75. static struct Tile (*tiles)[TileRows][TileCols];
  76. static void tilesMap(const char *path) {
  77. int fd = open(path, O_RDONLY);
  78. if (fd < 0) err(EX_NOINPUT, "%s", path);
  79. struct stat stat;
  80. int error = fstat(fd, &stat);
  81. if (error) err(EX_IOERR, "%s", path);
  82. if ((size_t)stat.st_size < TilesSize) {
  83. errx(EX_DATAERR, "%s: truncated tiles", path);
  84. }
  85. tiles = mmap(NULL, TilesSize, PROT_READ, MAP_SHARED, fd, 0);
  86. if (tiles == MAP_FAILED) err(EX_OSERR, "mmap");
  87. close(fd);
  88. error = madvise(tiles, TilesSize, MADV_RANDOM);
  89. if (error) err(EX_OSERR, "madvise");
  90. }
  91. static void render(uint32_t tileX, uint32_t tileY) {
  92. uint32_t width = CellCols * font.glyph.width;
  93. uint32_t height = CellRows * font.glyph.height;
  94. pngHead(stdout, width, height, 8, PNGIndexed);
  95. pngPalette(stdout, (uint8_t *)Palette, sizeof(Palette));
  96. uint8_t data[height][1 + width];
  97. memset(data, PNGNone, sizeof(data));
  98. uint32_t widthBytes = (font.glyph.width + 7) / 8;
  99. uint8_t (*bits)[font.glyph.len][font.glyph.height][widthBytes];
  100. bits = (void *)glyphs;
  101. struct Tile *tile = &(*tiles)[tileY][tileX];
  102. for (uint32_t cellY = 0; cellY < CellRows; ++cellY) {
  103. for (uint32_t cellX = 0; cellX < CellCols; ++cellX) {
  104. uint8_t cell = tile->cells[cellY][cellX];
  105. uint8_t fg = tile->colors[cellY][cellX] & 0x0F;
  106. uint8_t bg = tile->colors[cellY][cellX] >> 4;
  107. uint32_t glyphX = font.glyph.width * cellX;
  108. uint32_t glyphY = font.glyph.height * cellY;
  109. for (uint32_t y = 0; y < font.glyph.height; ++y) {
  110. for (uint32_t x = 0; x < font.glyph.width; ++x) {
  111. uint8_t bit = (*bits)[cell][y][x / 8] >> (7 - x % 8) & 1;
  112. data[glyphY + y][1 + glyphX + x] = (bit ? fg : bg);
  113. }
  114. }
  115. }
  116. }
  117. pngData(stdout, (uint8_t *)data, sizeof(data));
  118. pngTail(stdout);
  119. }
  120. int main(int argc, char *argv[]) {
  121. const char *fontPath = "default8x16.psfu";
  122. const char *dataPath = "torus.dat";
  123. uint32_t tileX = TileInitX;
  124. uint32_t tileY = TileInitY;
  125. int opt;
  126. while (0 < (opt = getopt(argc, argv, "d:f:x:y:"))) {
  127. switch (opt) {
  128. break; case 'd': dataPath = optarg;
  129. break; case 'f': fontPath = optarg;
  130. break; case 'x': tileX = strtoul(optarg, NULL, 0) % TileCols;
  131. break; case 'y': tileY = strtoul(optarg, NULL, 0) % TileRows;
  132. break; default: return EX_USAGE;
  133. }
  134. }
  135. fontLoad(fontPath);
  136. tilesMap(dataPath);
  137. render(tileX, tileY);
  138. return EX_OK;
  139. }