First stab at V6 semi-support through Blorb in curses. Things are distorted.
authorDavid Griffith <dave@661.org>
Wed, 17 Jul 2019 10:06:14 +0000 (03:06 -0700)
committerDavid Griffith <dave@661.org>
Wed, 17 Jul 2019 10:12:51 +0000 (03:12 -0700)
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.

src/blorb/blorb.h
src/blorb/blorblib.c
src/curses/ux_pic.c

index 4bb4eedaef46fd347afbefd5d5608384812312c0..6b10b0497f4e19d57a7d5ea3392c1f0f111ecabf 100644 (file)
 /* 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 <limits.h>
 #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. */
 
index 7ed6296a9c81ce651648e60dcb42e9945642c2cc..972b7ce26b47868afd842ae590059b0753139c7c 100644 (file)
@@ -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)
 {
index 9d20479024a39048b1c855c5683425a9d83de669..a82f9b25060756e1872810304da3a99fd8ef116b 100644 (file)
@@ -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;
 }