diff --git a/include/tile2x11.h b/include/tile2x11.h index 34ac01e75..3f16285e2 100644 --- a/include/tile2x11.h +++ b/include/tile2x11.h @@ -13,6 +13,10 @@ typedef struct { unsigned long tile_width; unsigned long tile_height; unsigned long ntiles; + unsigned long per_row; } x11_header; +/* how wide each row in the tile file is, in tiles */ +#define TILES_PER_ROW (40) + #endif /* TILE2X11_H */ diff --git a/include/winX.h b/include/winX.h index 38c9a7d44..7ded01856 100644 --- a/include/winX.h +++ b/include/winX.h @@ -56,6 +56,8 @@ struct tile_map_info_t { unsigned short glyphs[ROWNO][COLNO]; /* Saved glyph numbers. */ GC white_gc; GC black_gc; + unsigned long image_width; /* dimensions of tile image */ + unsigned long image_height; }; struct map_info_t { diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index 821540f3a..9eafac677 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -668,8 +668,8 @@ load_img.o: ../win/gem/load_img.c ../include/load_img.h $(CC) $(CFLAGS) -c ../win/gem/load_img.c tile.o: tile.c $(HACK_H) qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) ../include/func_tab.h \ - ../include/dlb.h ../include/patchlevel.h ../include/qt_win.h \ - ../include/qt_clust.h ../include/qt_kde0.h \ + ../include/dlb.h ../include/patchlevel.h ../include/tile2x11.h \ + ../include/qt_win.h ../include/qt_clust.h ../include/qt_kde0.h \ ../include/qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc $(CXX) $(CXXFLAGS) -c ../win/Qt/qt_win.cpp qt_clust.o: ../win/Qt/qt_clust.cpp ../include/qt_clust.h diff --git a/win/Qt/qt_win.cpp b/win/Qt/qt_win.cpp index 105fb96e4..649318083 100644 --- a/win/Qt/qt_win.cpp +++ b/win/Qt/qt_win.cpp @@ -56,6 +56,7 @@ extern "C" { #include "func_tab.h" #include "dlb.h" #include "patchlevel.h" +#include "tile2x11.h" #undef Warning #undef red #undef green @@ -4178,10 +4179,10 @@ NetHackQtGlyphs::NetHackQtGlyphs() tiles_per_row = 40; } } else { - tiles_per_row = 1; - if (img.height()%total_tiles_used) { - impossible("Tile file \"%s\" has %d lines, not multiple of glyph count (%d)", - tile_file, img.height(), total_tiles_used); + tiles_per_row = TILES_PER_ROW; + if (img.width()%tiles_per_row) { + impossible("Tile file \"%s\" has %d columns, not multiple of row count (%d)", + tile_file, img.height(), tiles_per_row); } } int rows = ((total_tiles_used+tiles_per_row-1) / tiles_per_row); diff --git a/win/X11/tile2x11.c b/win/X11/tile2x11.c index 746001dc3..a2542135d 100644 --- a/win/X11/tile2x11.c +++ b/win/X11/tile2x11.c @@ -15,7 +15,7 @@ x11_header header; -unsigned char tile_bytes[TILE_X*TILE_Y*MAX_GLYPH]; +unsigned char tile_bytes[TILE_X*TILE_Y*(MAX_GLYPH+TILES_PER_ROW)]; unsigned char *curr_tb = tile_bytes; unsigned char x11_colormap[MAXCOLORMAPSIZE][3]; @@ -44,8 +44,9 @@ pix_to_colormap(pix) /* Convert the tiles in the file to our format of bytes. */ static unsigned long -convert_tiles(tb_ptr) +convert_tiles(tb_ptr, total) unsigned char **tb_ptr; /* pointer to a tile byte pointer */ + unsigned long total; /* total tiles so far */ { unsigned char *tb = *tb_ptr; unsigned long count = 0; @@ -54,12 +55,20 @@ convert_tiles(tb_ptr) while (read_text_tile(tile)) { count++; - for (y = 0; y < TILE_Y; y++) + total++; + for (y = 0; y < TILE_Y; y++) { for (x = 0; x < TILE_X; x++) - *tb++ = pix_to_colormap(tile[y][x]); + tb[x] = pix_to_colormap(tile[y][x]); + tb += TILE_X * header.per_row; + } + + /* repoint at the upper-left corner of the next tile */ + *tb_ptr += TILE_X; + if (header.per_row == 1 || (total % header.per_row) == 0) + *tb_ptr += TILE_X * (TILE_Y - 1) * header.per_row; + tb = *tb_ptr; } - *tb_ptr = tb; /* update return val */ return count; } @@ -108,9 +117,9 @@ process_file(fname) if (!fopen_text_file(fname, RDTMODE)) { Fprintf(stderr, "can't open file \"%s\"\n", fname); exit(1); - } + } merge_text_colormap(); - count = convert_tiles(&curr_tb); + count = convert_tiles(&curr_tb, header.ntiles); Fprintf(stderr, "%s: %lu tiles\n", fname, count); header.ntiles += count; fclose_text_file(); @@ -122,7 +131,7 @@ static int xpm_write(fp) FILE *fp; { - int i,j,n; + int i, j, n; if (header.ncolors > 64) { Fprintf(stderr, "Sorry, only configured for up to 64 colors\n"); @@ -130,34 +139,32 @@ FILE *fp; /* All you need to do is add more char per color - below */ } - fprintf(fp, "/* XPM */\n"); - fprintf(fp, "static char* nhtiles[] = {\n"); - fprintf(fp, "\"%lu %lu %lu %d\",\n", - header.tile_width, - header.tile_height*header.ntiles, + Fprintf(fp, "/* XPM */\n"); + Fprintf(fp, "static char* nhtiles[] = {\n"); + Fprintf(fp, "\"%lu %lu %lu %d\",\n", + header.tile_width*header.per_row, + (header.tile_height*header.ntiles)/header.per_row, header.ncolors, 1 /* char per color */); for (i = 0; i < header.ncolors; i++) - fprintf(fp, "\"%c c #%02x%02x%02x\",\n", + Fprintf(fp, "\"%c c #%02x%02x%02x\",\n", i+'0', /* just one char per color */ x11_colormap[i][0], x11_colormap[i][1], x11_colormap[i][2]); - n=0; - for (i = 0; i < header.tile_height*header.ntiles; i++) { - fprintf(fp, "\""); - for (j = 0; j < header.tile_width; j++) { + n = 0; + for (i = 0; i < (header.tile_height*header.ntiles)/header.per_row; i++) { + Fprintf(fp, "\""); + for (j = 0; j < header.tile_width*header.per_row; j++) { /* just one char per color */ fputc(tile_bytes[n++]+'0', fp); } - if (j==header.tile_width-1) - fprintf(fp, "\"\n"); - else - fprintf(fp, "\",\n"); + + Fprintf(fp, "\",\n"); } - return fprintf(fp, "};\n")>=0; + return fprintf(fp, "};\n") >= 0; } #endif /* USE_XPM */ @@ -169,11 +176,12 @@ main(argc, argv) FILE *fp; int i; - header.version = 1; + header.version = 2; /* version 1 had no per_row field */ header.ncolors = 0; header.tile_width = TILE_X; header.tile_height = TILE_Y; header.ntiles = 0; /* updated as we read in files */ + header.per_row = TILES_PER_ROW; if (argc == 1) { Fprintf(stderr, "usage: %s txt_file1 [txt_file2 ...]\n", argv[0]); @@ -184,12 +192,20 @@ main(argc, argv) if (!fp) { Fprintf(stderr, "can't open output file\n"); exit(1); - } + } + + /* don't leave garbage at end of partial row */ + (void) memset((genericptr_t)tile_bytes, 0, sizeof(tile_bytes)); for (i = 1; i < argc; i++) process_file(argv[i]); Fprintf(stderr, "Total tiles: %ld\n", header.ntiles); + /* round size up to the end of the row */ + if ((header.ntiles % header.per_row) != 0) { + header.ntiles += header.per_row - (header.ntiles % header.per_row); + } + #ifdef USE_XPM if (xpm_write(fp) == 0) { Fprintf(stderr, "can't write XPM file\n"); @@ -199,7 +215,7 @@ main(argc, argv) if (fwrite((char *)&header, sizeof(x11_header), 1, fp) == 0) { Fprintf(stderr, "can't open output header\n"); exit(1); - } + } if (fwrite((char *)x11_colormap, 1, header.ncolors*3, fp) == 0) { Fprintf(stderr, "can't write output colormap\n"); diff --git a/win/X11/winmap.c b/win/X11/winmap.c index af83f100e..dda4685be 100644 --- a/win/X11/winmap.c +++ b/win/X11/winmap.c @@ -206,11 +206,11 @@ post_process_tiles() Display *dpy = XtDisplay(toplevel); unsigned int width, height; - height = tile_height * tile_count; - width = tile_width; - if (tile_image == 0) return; /* no tiles */ + height = tile_image->height; + width = tile_image->width; + tile_pixmap = XCreatePixmap(dpy, XtWindow(toplevel), width, height, @@ -239,7 +239,10 @@ static boolean init_tiles(wp) struct xwindow *wp; { -#ifndef USE_XPM +#ifdef USE_XPM + XpmAttributes attributes; + int errorcode; +#else FILE *fp = (FILE *)0; x11_header header; unsigned char *cp, *colormap = (unsigned char *)0; @@ -248,13 +251,14 @@ init_tiles(wp) XColor *colors = (XColor *)0; int i, x, y; int bitmap_pad; - unsigned int image_height, image_width; int ddepth; #endif + char buf[BUFSZ]; Display *dpy = XtDisplay(toplevel); Screen *screen = DefaultScreenOfDisplay(dpy); struct map_info_t *map_info = (struct map_info_t *)0; struct tile_map_info_t *tile_info = (struct tile_map_info_t *)0; + unsigned int image_height = 0, image_width = 0; boolean result = TRUE; XGCValues values; XtGCMask mask; @@ -269,54 +273,63 @@ init_tiles(wp) sizeof(struct tile_map_info_t)); #ifdef USE_XPM - { - char buf[BUFSZ]; - XpmAttributes attributes; - int errorcode; + attributes.valuemask = XpmCloseness; + attributes.closeness = 25000; - attributes.valuemask = XpmCloseness; - attributes.closeness = 25000; + errorcode = XpmReadFileToImage(dpy, appResources.tile_file, + &tile_image, 0, &attributes); - errorcode=XpmReadFileToImage(dpy,appResources.tile_file,&tile_image,0,&attributes); + if (errorcode == XpmColorFailed) { + Sprintf(buf, "Insufficient colors available to load %s.", + appResources.tile_file); + X11_raw_print(buf); + X11_raw_print("Try closing other colorful applications and restart."); + X11_raw_print("Attempting to load with inferior colors."); + attributes.closeness = 50000; + errorcode = XpmReadFileToImage(dpy, appResources.tile_file, + &tile_image, 0, &attributes); + } + if (errorcode != XpmSuccess) { if (errorcode == XpmColorFailed) { - Sprintf(buf, "Insufficient colors available to load %s.",appResources.tile_file); + Sprintf(buf, "Insufficient colors available to load %s.", + appResources.tile_file); X11_raw_print(buf); - X11_raw_print("Try closing other colorful applications and restart."); - X11_raw_print("Attempting to load with inferior colors."); - attributes.closeness = 50000; - errorcode=XpmReadFileToImage(dpy,appResources.tile_file,&tile_image,0,&attributes); - } - - if (errorcode!=XpmSuccess) { - if (errorcode == XpmColorFailed) { - Sprintf(buf, "Insufficient colors available to load %s.",appResources.tile_file); - X11_raw_print(buf); - } else { - Sprintf(buf, "Failed to load %s: %s",appResources.tile_file, - XpmGetErrorString(errorcode)); - X11_raw_print(buf); - } - result = FALSE; - X11_raw_print("Switching to text-based mode."); - goto tiledone; - } - - if (tile_image->height%total_tiles_used != 0) { - Sprintf(buf, - "%s is not a multiple of %d (the number of tiles) pixels high", - appResources.tile_file, total_tiles_used); + } else { + Sprintf(buf, "Failed to load %s: %s", appResources.tile_file, + XpmGetErrorString(errorcode)); X11_raw_print(buf); - XDestroyImage(tile_image); - tile_image = 0; - result = FALSE; - goto tiledone; } + result = FALSE; + X11_raw_print("Switching to text-based mode."); + goto tiledone; + } - /* infer tile dimensions from image size */ - tile_count=total_tiles_used; - tile_width=tile_image->width; - tile_height=tile_image->height/tile_count; + /* assume a fixed number of tiles per row */ + if (tile_image->width % TILES_PER_ROW != 0) { + Sprintf(buf, + "%s is not a multiple of %d (number of tiles/row) pixels wide", + appResources.tile_file, TILES_PER_ROW); + X11_raw_print(buf); + XDestroyImage(tile_image); + tile_image = 0; + result = FALSE; + goto tiledone; + } + + /* infer tile dimensions from image size, assume square tiles */ + image_width = tile_image->width; + image_height = tile_image->height; + tile_width = image_width / TILES_PER_ROW; + tile_height = tile_width; + tile_count = (image_width * image_height) / (tile_width * tile_height); + + if (tile_count < total_tiles_used) { + Sprintf(buf, "%s incomplete, expecting %d tiles, found %d", + appResources.tile_file, total_tiles_used, tile_count); + X11_raw_print(buf); + result = FALSE; + goto tiledone; } #else /* any less than 16 colours makes tiles useless */ @@ -340,12 +353,21 @@ init_tiles(wp) goto tiledone; } + if (header.version != 2) { + Sprintf(buf, "Wrong tile file version, expected 2, got %lu", + header.version); + X11_raw_print(buf); + result = FALSE; + goto tiledone; + } + # ifdef VERBOSE - fprintf(stderr, "X11 tile file:\n version %ld\n ncolors %ld\n tile width %ld\n tile height %ld\n ntiles %ld\n", + fprintf(stderr, "X11 tile file:\n version %ld\n ncolors %ld\n tile width %ld\n tile height %ld\n per row %ld\n ntiles %ld\n", header.version, header.ncolors, header.tile_width, header.tile_height, + header.per_row, header.ntiles); # endif @@ -374,9 +396,8 @@ init_tiles(wp) if (!XAllocColor(dpy, DefaultColormapOfScreen(screen), &colors[i]) && !nhApproxColor(screen, DefaultColormapOfScreen(screen), (char *)0, &colors[i])) { - char buf[BUFSZ]; Sprintf(buf, "%dth out of %ld color allocation failed", - i, header.ncolors); + i, header.ncolors); X11_raw_print(buf); result = FALSE; goto tiledone; @@ -388,8 +409,11 @@ init_tiles(wp) * This alloc() and the one below require 32-bit ints, since tile_bytes * is currently ~200k and alloc() takes an int */ - tile_bytes = (unsigned char *) alloc((unsigned)header.ntiles*size); tile_count = header.ntiles; + if ((tile_count % header.per_row) != 0) { + tile_count += header.per_row - (tile_count % header.per_row); + } + tile_bytes = (unsigned char *) alloc((unsigned)tile_count*size); if (fread((char *) tile_bytes, size, tile_count, fp) != tile_count) { X11_raw_print("read of tile bytes failed"); result = FALSE; @@ -397,7 +421,6 @@ init_tiles(wp) } if (header.ntiles < total_tiles_used) { - char buf[BUFSZ]; Sprintf(buf, "tile file incomplete, expecting %d tiles, found %lu", total_tiles_used, header.ntiles); X11_raw_print(buf); @@ -414,8 +437,8 @@ init_tiles(wp) tile_height = header.tile_height; } - image_height = tile_height * tile_count; - image_width = tile_width; + image_height = tile_height * tile_count / header.per_row; + image_width = tile_width * header.per_row; /* calculate bitmap_pad */ if (ddepth > 16) @@ -444,19 +467,19 @@ init_tiles(wp) if (appResources.double_tile_size) { unsigned long *expanded_row = - (unsigned long *)alloc(sizeof(unsigned long)*(unsigned)tile_width); + (unsigned long *)alloc(sizeof(unsigned long)*(unsigned)image_width); tb = tile_bytes; for (y = 0; y < image_height; y++) { - for (x = 0; x < header.tile_width; x++) + for (x = 0; x < image_width/2; x++) expanded_row[2*x] = expanded_row[(2*x)+1] = colors[*tb++].pixel; - for (x = 0; x < tile_width; x++) + for (x = 0; x < image_width; x++) XPutPixel(tile_image, x, y, expanded_row[x]); y++; /* duplicate row */ - for (x = 0; x < tile_width; x++) + for (x = 0; x < image_width; x++) XPutPixel(tile_image, x, y, expanded_row[x]); } free((genericptr_t)expanded_row); @@ -489,12 +512,8 @@ init_tiles(wp) */ mask = GCFunction | GCForeground | GCGraphicsExposures; values.graphics_exposures = False; -#if 1 values.foreground = WhitePixelOfScreen(screen) ^ XGetPixel(tile_image, 0, tile_height*glyph2tile[cmap_to_glyph(S_corr)]); -#else - values.foreground = ~((unsigned long) 0); -#endif values.function = GXxor; tile_info->white_gc = XtGetGC(wp->w, mask, &values); @@ -502,7 +521,7 @@ init_tiles(wp) values.function = GXCopy; values.graphics_exposures = False; tile_info->black_gc = XtGetGC(wp->w, mask, &values); -#endif +#endif /* USE_WHITE */ tiledone: #ifndef USE_XPM @@ -517,6 +536,8 @@ tiledone: map_info->square_width = tile_width; map_info->square_ascent = 0; map_info->square_lbearing = 0; + tile_info->image_width = image_width; + tile_info->image_height = image_height; } else { if (tile_info) free((genericptr_t)tile_info); tile_info = 0; @@ -905,7 +926,7 @@ get_char_info(wp) #ifdef VERBOSE printf("Font information:\n"); - printf("fid = %d, direction = %d\n", fs->fid, fs->direction); + printf("fid = %ld, direction = %d\n", fs->fid, fs->direction); printf("first = %d, last = %d\n", fs->min_char_or_byte2, fs->max_char_or_byte2); printf("all chars exist? %s\n", fs->all_chars_exist?"yes":"no"); @@ -917,7 +938,7 @@ get_char_info(wp) fs->max_bounds.lbearing, fs->max_bounds.rbearing, fs->max_bounds.width, fs->max_bounds.ascent, fs->max_bounds.descent, fs->max_bounds.attributes); - printf("per_char = 0x%x\n", fs->per_char); + printf("per_char = 0x%lx\n", (unsigned long) fs->per_char); printf("Text: (max) width = %d, height = %d\n", map_info->square_width, map_info->square_height); #endif @@ -1174,28 +1195,26 @@ map_update(wp, start_row, stop_row, start_col, stop_col, inverted) if (map_info->is_tile) { struct tile_map_info_t *tile_map = map_info->mtype.tile_map; int cur_col; - Display* dpy=XtDisplay(wp->w); - Screen* screen=DefaultScreenOfDisplay(dpy); + Display* dpy = XtDisplay(wp->w); + Screen* screen = DefaultScreenOfDisplay(dpy); for (row = start_row; row <= stop_row; row++) { for (cur_col = start_col; cur_col <= stop_col; cur_col++) { int glyph = tile_map->glyphs[row][cur_col]; int tile = glyph2tile[glyph]; + int src_x, src_y; int dest_x = cur_col * map_info->square_width; int dest_y = row * map_info->square_height; + src_x = (tile % TILES_PER_ROW) * tile_width; + src_y = (tile / TILES_PER_ROW) * tile_height; XCopyArea(dpy, tile_pixmap, XtWindow(wp->w), - tile_map->black_gc, /* no grapics_expose */ - 0, - tile * map_info->square_height, - tile_width, tile_height, - dest_x,dest_y); + tile_map->black_gc, /* no grapics_expose */ + src_x, src_y, + tile_width, tile_height, + dest_x, dest_y); - if (glyph_is_pet(glyph) -#ifdef TEXTCOLOR - && iflags.hilite_pet -#endif - ) { + if (glyph_is_pet(glyph) && iflags.hilite_pet) { /* draw pet annotation (a heart) */ XSetForeground(dpy, tile_map->black_gc, pet_annotation.foreground); XSetClipOrigin(dpy, tile_map->black_gc, dest_x, dest_y);