From: David Griffith Date: Wed, 17 Jul 2019 10:06:14 +0000 (-0700) Subject: First stab at V6 semi-support through Blorb in curses. Things are distorted. X-Git-Url: https://scope-eye.net/git/?a=commitdiff_plain;h=12ec3686f2268cd877745d2639de67c68c346ddb;p=liskon_frotz.git First stab at V6 semi-support through Blorb in curses. Things are distorted. Right now, the code detects PNG and JPG images. However, stuff seems to be done only for Infocom's games and the blorbs made up for them. Even then, the results are distorted. This may be because rectangle chunks aren't being processed and the code depends on some chunks that aren't found in post-Infocom V6 blorbs. Still, here's something to play with. --- diff --git a/src/blorb/blorb.h b/src/blorb/blorb.h index 4bb4eed..6b10b04 100644 --- a/src/blorb/blorb.h +++ b/src/blorb/blorb.h @@ -12,12 +12,8 @@ /* Things you (the porter) have to edit: */ /* As you might expect, uint32 must be a 32-bit unsigned numeric type, - and uint16 a 16-bit unsigned numeric type. You should also uncomment - exactly one of the two ENDIAN definitions. */ + and uint16 a 16-bit unsigned numeric type. */ -/* #define BLORB_BIG_ENDIAN */ - -#define BLORB_LITTLE_ENDIAN #include #if UINT_MAX == (1UL<<32)-1UL typedef unsigned int uint32; @@ -149,6 +145,11 @@ typedef struct bb_zheader_struct { This type is opaque for normal interpreter use. */ typedef struct bb_map_struct bb_map_t; + +/* This can be handy elsewhere. */ +extern int bigendian; + + /* Function declarations. These functions are of fairly general use; they would apply to any Blorb file. */ diff --git a/src/blorb/blorblib.c b/src/blorb/blorblib.c index 7ed6296..972b7ce 100644 --- a/src/blorb/blorblib.c +++ b/src/blorb/blorblib.c @@ -16,7 +16,8 @@ static int lib_inited = FALSE; static bb_err_t bb_initialize_map(bb_map_t *map); static bb_err_t bb_initialize(void); static int sortsplot(const void *p1, const void *p2); -static int bigendian; + +int bigendian; static uint16 bb_native2(uint16 v) { diff --git a/src/curses/ux_pic.c b/src/curses/ux_pic.c index 9d20479..a82f9b2 100644 --- a/src/curses/ux_pic.c +++ b/src/curses/ux_pic.c @@ -41,6 +41,8 @@ #define PIC_HEADER_WIDTH 2 #define PIC_HEADER_HEIGHT 4 +bb_map_t *blorb_map; + static void safe_mvaddch(int, int, int); static struct { @@ -53,18 +55,6 @@ static struct { static int num_pictures = 0; -static unsigned char lookupb(unsigned char *p, int n) -{ - return p[n]; -} - - -static unsigned short lookupw(unsigned char *p, int n) -{ - return (p[n + 1] << 8) | p[n]; -} - - /* * Do a rounding division, rounding to even if fraction part is 1/2. * We assume x and y are nonnegative. @@ -81,75 +71,103 @@ static int round_div(int x, int y) } -bool unix_init_pictures (void) -{ - FILE *file = NULL; - int success = FALSE; - unsigned char gheader[16]; - unsigned char *raw_info = NULL; +extern int bigendian; - char *filename; - const char *basename, *dotpos; - int namelen; +static void swapbytes(void *object, size_t size) +{ + unsigned char *start, *end; + unsigned char swap; + + if(!bigendian) { + for (start = (unsigned char *)object, end = start + size - 1; start < end; ++start, --end ) { + swap = *start; + *start = *end; + *end = swap; + } + } +} - if ((filename = malloc(2 * strlen(f_setup.story_name) + 10)) == NULL) - return FALSE; - basename = strrchr(f_setup.story_name, '/'); - if (basename) basename++; else basename = f_setup.story_name; - dotpos = strrchr(basename, '.'); - namelen = (dotpos ? dotpos - basename : (int) strlen(basename)); - sprintf(filename, "%.*sgraphics/%.*s.mg1", - (int)(basename - f_setup.story_name), f_setup.story_name, namelen, basename); - - do { - int i, entry_size, flags, x_scale, y_scale; - - if (((file = fopen (filename, "rb")) == NULL) - || (fread(&gheader, sizeof (gheader), 1, file) != 1)) - break; - - num_pictures = lookupw(gheader, PIC_FILE_HEADER_NUM_IMAGES); - entry_size = lookupb(gheader, PIC_FILE_HEADER_ENTRY_SIZE); - flags = lookupb(gheader, PIC_FILE_HEADER_FLAGS); - - raw_info = malloc(num_pictures * entry_size); - - if (fread(raw_info, num_pictures * entry_size, 1, file) != 1) - break; - - pict_info = malloc((num_pictures + 1) * sizeof(*pict_info)); - pict_info[0].z_num = 0; - pict_info[0].height = num_pictures; - pict_info[0].width = lookupw(gheader, PIC_FILE_HEADER_VERSION); - - y_scale = 200; - x_scale = (flags & 0x08) ? 640 : 320; - - /* Copy and scale. */ - for (i = 1; i <= num_pictures; i++) { - unsigned char *p = raw_info + entry_size * (i - 1); - pict_info[i].z_num = lookupw(p, PIC_HEADER_NUMBER); - pict_info[i].orig_height = lookupw(p, PIC_HEADER_HEIGHT); - pict_info[i].orig_width = lookupw(p, PIC_HEADER_WIDTH); - - pict_info[i].height = round_div(pict_info[i].orig_height * - h_screen_rows, y_scale); - pict_info[i].width = round_div(pict_info[i].orig_width * - h_screen_cols, x_scale); - - /* Don't let dimensions get rounded to nothing. */ - if (pict_info[i].orig_height && !pict_info[i].height) - pict_info[1].height = 1; - if (pict_info[i].orig_width && !pict_info[i].width) - pict_info[i].width = 1; +bool unix_init_pictures (void) +{ + int maxlegalpic = 0; + int i, x_scale, y_scale; + bool success = FALSE; + + unsigned char png_magic[8] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; + unsigned char ihdr_name[] = "IHDR"; + unsigned char jpg_magic[3] = {0xFF, 0xD8, 0xFF}; + unsigned char jfif_name[5] = {'J', 'F', 'I', 'F', 0x00}; + + bb_result_t res; + + uint32 pos; + + if (blorb_map == NULL) return FALSE; + + bb_count_resources(blorb_map, bb_ID_Pict, &num_pictures, NULL, &maxlegalpic); + pict_info = malloc((num_pictures + 1) * sizeof(*pict_info)); + pict_info[0].z_num = 0; + pict_info[0].height = num_pictures; + pict_info[0].width = bb_get_release_num(blorb_map); + + y_scale = 200; + x_scale = 320; + + for (i = 1; i <= num_pictures; i++) { + if (bb_load_resource(blorb_map, bb_method_Memory, &res, bb_ID_Pict, i) == bb_err_None) { + /* Copy and scale. */ + pict_info[i].z_num = i; + /* Check to see if we're dealing with a PNG file. */ + if (memcmp(res.data.ptr, png_magic, 8) == 0) { + /* Check for IHDR chunk. If it's not there, PNG file is invalid. */ + if (memcmp(res.data.ptr+12, ihdr_name, 4) == 0) { + pict_info[i].orig_width = + (*((unsigned char *)res.data.ptr+16) << 24) + + (*((unsigned char *)res.data.ptr+17) << 16) + + (*((unsigned char *)res.data.ptr+18) << 8) + + (*((unsigned char *)res.data.ptr+19) << 0); + pict_info[i].orig_height = + (*((unsigned char *)res.data.ptr+20) << 24) + + (*((unsigned char *)res.data.ptr+21) << 16) + + (*((unsigned char *)res.data.ptr+22) << 8) + + (*((unsigned char *)res.data.ptr+23) << 0); + } + } else if (memcmp(res.data.ptr, jpg_magic, 3) == 0) { /* Is it JPEG? */ + if (memcmp(res.data.ptr+6, jfif_name, 5) == 0) { /* Look for JFIF */ + pos = 11; + while (pos < res.length) { + pos++; + if (pos >= res.length) break; /* Avoid segfault */ + if (*((unsigned char *)res.data.ptr+pos) != 0xFF) continue; + if (*((unsigned char *)res.data.ptr+pos+1) != 0xC0) continue; + pict_info[i].orig_width = + (*((unsigned char *)res.data.ptr+pos+7)*256) + + *((unsigned char *)res.data.ptr+pos+8); + pict_info[i].orig_height = + (*((unsigned char *)res.data.ptr+pos+5)*256) + + *((unsigned char *)res.data.ptr+pos+6); + } /* while */ + } /* JFIF */ + } /* JPEG */ + } + if (bigendian) { + swapbytes(&pict_info[i].orig_width, 4); + swapbytes(&pict_info[i].orig_height, 4); } + pict_info[i].height = round_div(pict_info[i].orig_height * + h_screen_rows, y_scale); + pict_info[i].width = round_div(pict_info[i].orig_width * + h_screen_cols, x_scale); + + /* Don't let dimensions get rounded to nothing. */ + if (pict_info[i].orig_height && !pict_info[i].height) + pict_info[1].height = 1; + if (pict_info[i].orig_width && !pict_info[i].width) + pict_info[i].width = 1; + success = TRUE; - } while (0); - if (file) - fclose(file); - if (raw_info) - free(raw_info); + } /* for */ return success; }