/* NetHack 3.7 tile2bmp.c $NHDT-Date: 1737281026 2025/01/19 02:03:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.51 $ */ /* Copyright (c) NetHack PC Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* * Edit History: * * Initial Creation M.Allison 1994/01/11 * 256 colour bmp and statue support M.Allison 2015/04/19 * */ #ifndef __GNUC__ #include "win32api.h" #endif #include "config.h" #include "hacklib.h" #include "tile.h" extern void monst_globals_init(void); extern void objects_globals_init(void); static int examine_tilefiles(void); static int set_tilefile_path(const char *, const char *, char *, size_t); #if defined(_MSC_VER) && defined(_WIN64) #define UNALIGNED_POINTER __unaligned #else #define UNALIGNED_POINTER #endif #define COLORS_IN_USE 256 #define BITCOUNT 8 /* GCC fix by Paolo Bonzini 1999/03/28 */ #ifdef __GNUC__ #define PACK __attribute__((packed)) #else #define PACK #endif static short leshort(short x) { #ifdef __BIG_ENDIAN__ return ((x & 0xff) << 8) | ((x >> 8) & 0xff); #else return x; #endif } static int32_t lelong(int32_t x) { #ifdef __BIG_ENDIAN__ return ((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff); #else return x; #endif } #ifdef __GNUC__ typedef struct tagBMIH { uint32_t biSize; int32_t biWidth; int32_t biHeight; uint16_t biPlanes; uint16_t biBitCount; uint32_t biCompression; uint32_t biSizeImage; int32_t biXPelsPerMeter; int32_t biYPelsPerMeter; uint32_t biClrUsed; uint32_t biClrImportant; } PACK BITMAPINFOHEADER; typedef struct tagBMFH { uint16_t bfType; uint32_t bfSize; uint16_t bfReserved1; uint16_t bfReserved2; uint32_t bfOffBits; } PACK BITMAPFILEHEADER; typedef struct tagRGBQ { uint8_t rgbBlue; uint8_t rgbGreen; uint8_t rgbRed; uint8_t rgbReserved; } PACK RGBQUAD; #define BI_RGB 0L #define BI_RLE8 1L #define BI_RLE4 2L #define BI_BITFIELDS 3L #endif /* __GNUC__ */ #define RGBQUAD_COUNT 256 #pragma pack(1) struct tagBMP { BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmih; RGBQUAD bmaColors[RGBQUAD_COUNT]; uchar packtile; /* start */ } PACK bmp, *newbmp; #pragma pack() FILE *tibfile2; pixel tilepixels[TILE_Y][TILE_X]; static void build_bmfh(BITMAPFILEHEADER *); static void build_bmih(UNALIGNED_POINTER BITMAPINFOHEADER *); static void build_bmptile(pixel(*) [TILE_X]); #define TILESETS 1 static const char *const relative_tiledir = "../win/share/"; /* monsters must be first because main uses it twice */ const char *const tilefilenames[TILESETS][3] = { {"monsters.txt", "objects.txt", "other.txt"}, #if 0 {"mon32.txt", "obj32.txt", "oth32.txt"}, {"mon64.txt", "obj64.txt", "oth64.txt"}, #endif }; int tilecnt[SIZE(tilefilenames[0])]; int tilefileset = 0; int tiles_counted; int max_x, max_y; int magictileno = 0, bmpsize; int num_colors = 0; int max_tiles_in_row = 40; int tiles_in_row; int filenum; int initflag; int pass; int yoffset, xoffset; char bmpname[128]; FILE *fp; DISABLE_WARNING_UNREACHABLE_CODE int main(int argc, char *argv[]) { int i, j, number_of_rows, number_in_final_row; uchar *c; char tilefile_full_path[256] = { 0 }; if (argc != 2) { Fprintf(stderr, "usage: %s outfile.bmp\n", argv[0]); exit(EXIT_FAILURE); } else if (argv[1] == 0 || strlen(argv[1]) >= sizeof bmpname - 1) { Fprintf(stderr, "invalid output bmp file name %s, aborting.\n", argv[0]); exit(EXIT_FAILURE); } else { strcpy(bmpname, argv[1]); } objects_globals_init(); monst_globals_init(); /* tilefileset = (TILE_X == 64) ? 2 : (TILE_X == 32) ? 1 : 0; */ tilefileset = 0; if (!examine_tilefiles()) { Fprintf(stderr, "unable to open all of the tile files, aborting.\n"); exit(EXIT_FAILURE); } for (i = 0; i < SIZE(tilecnt); ++i) magictileno += tilecnt[i]; /* count monsters twice for grayscale variation */ magictileno += tilecnt[0]; max_x = TILE_X * max_tiles_in_row; max_y = ((TILE_Y * magictileno) / max_tiles_in_row) + TILE_Y; bmpsize = (sizeof bmp - sizeof bmp.packtile) + (max_y * (max_x * sizeof(uchar))); newbmp = malloc(bmpsize); if (!newbmp) { printf("memory allocation failure, %d %d, aborting.\n", bmpsize, magictileno); exit(EXIT_FAILURE); } tiles_counted = 0; xoffset = yoffset = 0; initflag = 0; filenum = 0; pass = 0; fp = fopen(bmpname, "wb"); if (!fp) { printf("Error creating tile file %s, aborting.\n", bmpname); exit(EXIT_FAILURE); } while (pass < 4) { filenum = pass % SIZE(tilefilenames[tilefileset]); if (!set_tilefile_path(relative_tiledir, tilefilenames[tilefileset][filenum], tilefile_full_path, sizeof tilefile_full_path)) { Fprintf(stderr, "tile2bmp path issue %s %s %d\n", relative_tiledir, tilefilenames[tilefileset][filenum], (int) sizeof tilefile_full_path); exit(EXIT_FAILURE); } if (!fopen_text_file(tilefile_full_path, RDTMODE)) { Fprintf(stderr, "usage: tile2bmp (from the util directory)\n"); exit(EXIT_FAILURE); } num_colors = colorsinmap; if (num_colors > 62) { Fprintf(stderr, "too many colors (%d), aborting.\n", num_colors); exit(EXIT_FAILURE); } if (!initflag) { UNALIGNED_POINTER BITMAPINFOHEADER *bmih; build_bmfh(&bmp.bmfh); bmih = &bmp.bmih; build_bmih(bmih); for (i = 0; i < num_colors; i++) { bmp.bmaColors[i].rgbRed = ColorMap[CM_RED][i]; bmp.bmaColors[i].rgbGreen = ColorMap[CM_GREEN][i]; bmp.bmaColors[i].rgbBlue = ColorMap[CM_BLUE][i]; bmp.bmaColors[i].rgbReserved = 0; } *newbmp = bmp; for (i = 0; i < max_y; ++i) for (j = 0; j < max_x; ++j) { c = &newbmp->packtile + ((i * max_x) + j); *c = (uchar) 0; } initflag = 1; } set_grayscale(pass == 3); /* printf("Colormap initialized\n"); */ while (read_text_tile(tilepixels)) { if (tiles_counted >= magictileno) { Fprintf(stderr, "tile2bmp: more than %d tiles!\n", magictileno); exit(EXIT_FAILURE); } build_bmptile(tilepixels); tiles_counted++; xoffset += TILE_X; if (xoffset >= max_x) { yoffset += TILE_Y; xoffset = 0; } } (void) fclose_text_file(); ++pass; } fwrite(newbmp, bmpsize, 1, fp); fclose(fp); number_of_rows = tiles_counted / max_tiles_in_row; number_in_final_row = tiles_counted % max_tiles_in_row; Fprintf(stderr, "Total of %d tiles written to %s, " "%d full rows of %d tiles", tiles_counted, bmpname, number_of_rows, max_tiles_in_row); if (number_in_final_row != 0) { Fprintf(stderr, ", final row %d has %d tile%s", number_of_rows + 1, number_in_final_row, number_in_final_row > 1 ? "s" : ""); } (void) fputs(".\n\n", stderr); free((genericptr_t) newbmp); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } RESTORE_WARNINGS static void build_bmfh(BITMAPFILEHEADER* pbmfh) { pbmfh->bfType = leshort(0x4D42); pbmfh->bfSize = lelong(bmpsize); pbmfh->bfReserved1 = (uint32_t) 0; pbmfh->bfReserved2 = (uint32_t) 0; pbmfh->bfOffBits = lelong(sizeof bmp.bmfh + sizeof bmp.bmih + (RGBQUAD_COUNT * sizeof(RGBQUAD))); } static void build_bmih(UNALIGNED_POINTER BITMAPINFOHEADER* pbmih) { uint16_t cClrBits; int w, h; pbmih->biSize = lelong(sizeof(bmp.bmih)); pbmih->biWidth = lelong(w = max_x); pbmih->biHeight = lelong(h = max_y); pbmih->biPlanes = leshort(1); pbmih->biBitCount = leshort(8); cClrBits = 8; if (cClrBits == 1) cClrBits = 1; else if (cClrBits <= 4) cClrBits = 4; else if (cClrBits <= 8) cClrBits = 8; else if (cClrBits <= 16) cClrBits = 16; else if (cClrBits <= 24) cClrBits = 24; else cClrBits = 32; pbmih->biCompression = lelong(BI_RGB); pbmih->biXPelsPerMeter = lelong(0); pbmih->biYPelsPerMeter = lelong(0); #if (TILE_X == 32) if (cClrBits < 24) pbmih->biClrUsed = lelong(1 << cClrBits); #else pbmih->biClrUsed = lelong(RGBQUAD_COUNT); #endif pbmih->biSizeImage = lelong(((w * cClrBits + 31) & ~31) / 8 * h); pbmih->biClrImportant = (uint32_t) 0; } static void build_bmptile(pixel(*pixels)[TILE_X]) { int cur_x, cur_y, cur_color, apply_color; int x, y; uchar *c; for (cur_y = 0; cur_y < TILE_Y; cur_y++) { for (cur_x = 0; cur_x < TILE_X; cur_x++) { for (cur_color = 0; cur_color < num_colors; cur_color++) { if (ColorMap[CM_RED][cur_color] == pixels[cur_y][cur_x].r && ColorMap[CM_GREEN][cur_color] == pixels[cur_y][cur_x].g && ColorMap[CM_BLUE][cur_color] == pixels[cur_y][cur_x].b) break; } if (cur_color >= num_colors) Fprintf(stderr, "color not in colormap! (tile #%d)\n", tiles_counted); y = (max_y - 1) - (cur_y + yoffset); apply_color = cur_color; x = cur_x + xoffset; c = &newbmp->packtile + ((y * max_x) + x); *c = (uchar) apply_color; } } } static int set_tilefile_path(const char *fdir, const char *fname, char *buf, size_t sz) { size_t consuming = 0; *buf = '\0'; consuming = strlen(fdir) + strlen(fname) + 1; if (consuming > sz) return 0; Strcpy(buf, fdir); Strcat(buf, fname); return 1; } static int examine_tilefiles(void) { FILE *fp2; int i, tiles_in_file; char tilefile_full_path[256]; for (i = 0; i < SIZE(tilefilenames[0]); ++i) { tiles_in_file = 0; if (!set_tilefile_path(relative_tiledir, tilefilenames[tilefileset][i], tilefile_full_path, sizeof tilefile_full_path)) { Fprintf(stderr, "tile2bmp path issue %s/%s %d\n", relative_tiledir, tilefilenames[tilefileset][i], (int) sizeof tilefile_full_path); return 0; } fp2 = fopen(tilefile_full_path, "r"); if (fp2) { char line[256]; while (fgets(line, sizeof line, fp2)) { if (!strncmp(line, "# tile ", 7)) tiles_in_file++; } (void) fclose(fp2); tilecnt[i] = tiles_in_file; } } return 1; } /*tile2bmp.c*/