/* * mdl -- display a DL animation (monochrome ST only) * * uses Setscreen flicker trick * * * * derived from xdl by: * Jonas Yngvesson * * which was derived from dltogl.c by: * George Phillips * * Support for user defined animation speed: * Per Beremark */ #include #include /* for malloc */ #include /* for getopt */ #include #include #define isneg16(x) ((x) & 0x8000) #define neg16(x) ((~(x) + 1) & 0x7fff) typedef struct { int version; int format; int images_per_screen; char title[21]; char author[21]; int num_screen; int num_command; } DL_info; int __default_mode__ = _IOBIN; /* force stdin binary (gcc) */ unsigned long pixels[256]; /* for colormap conversion */ char *myname = "mdl"; void usage (int); void colormap_setup (FILE *, int); extern int dl_flicker (unsigned char *, int, int, int, int, int, int, int, int *, int, int); /* pimg -> raster image sequence (intensities) */ /* nframes number of frames in pimg */ /* width width, pixels */ /* hight height, pixels */ /* beta for laplace filter */ /* maxrandom for random noise */ /* opt 0=no flicker, 1=flicker */ /* delay ms delay between images */ /* cmd -> commands (order to display frames) */ /* numcmd number of commands */ /* show print info to stdout if != 0 */ extern char *optarg; /* getopt stuff */ extern int optind; /*------------------------------*/ /* main */ /*------------------------------*/ void main (int argc, char *argv[]) { DL_info dlinfo; /* dl file info */ char *filename; FILE *fp; unsigned char *image_data; /* space for 1 screen from file */ unsigned char *img; /* space for all frames */ unsigned char *pimg; /* ptr to img */ long pimg_inc; /* increment to next frame in img */ int nframes; /* num of individual frames */ int ncommands; /* num of frames (= num frames in loop)*/ short gray; int width, height; int *cmd; /* space for command list */ int labelpos; int frame_freq; /* milliseconds per frame */ int fps = 25; /* frames per second */ int zoomflag = 0; int ival = 0; int errflg = 0; int do_flick = 1; int beta = 0; int noise = 0; int verbose = 0; int i, j; /* * parse command line... */ while ((i = getopt(argc, argv, "vszhr:i:b:n:")) != -1) { switch (i) { case 'v': /* verbose */ verbose++; break; case 's': /* single (no flicker)*/ do_flick = 0; break; case 'b': /* beta */ beta = atoi(optarg); if (beta < 0) beta = 0; break; case 'n': /* noise */ noise = atoi(optarg); if (noise < 0) noise = 0; if (noise > 255) noise = 255; break; case 'i': /* intensity adjust */ ival = atoi(optarg); if (ival < -254) ival = -254; if (ival > 254) ival = 254; break; case 'z': /* zoom */ zoomflag = 1; break; case 'h': /* help */ usage (0); break; /*NOTREACHED*/ case 'r': /* rate (fps) */ fps = atoi(optarg); if (fps < 1) fps = 1; if (fps > 100) fps = 100; break; case '?': default: errflg++; } } if (errflg) { usage(2); } /* * if no files, use stdin. otherwise open file */ if (argv[optind] == NULL) { fp = stdin; filename = "stdin"; } else if ((fp = fopen (argv[optind], "rb")) == NULL) { fprintf(stderr, "%s: can't open %s\n", myname, argv[1]); exit(1); } else { filename = argv[optind]; } /* * Check the version number... */ if ((dlinfo.version = fgetc(fp)) != 1 && dlinfo.version != 2) { fprintf(stderr, "%s: This file is in an unknown format.\n", myname); fprintf(stderr, "can only do .DL version 1 and 2 (this is %d).\n", dlinfo.version); exit(1); } /* * ...and the format. */ if (dlinfo.version == 1) dlinfo.format = 1; else dlinfo.format = fgetc(fp); switch (dlinfo.format) { case 0: /* large */ width = 320; height = 200; dlinfo.images_per_screen = 1; zoomflag = 0; break; case 1: /* medium */ if (zoomflag) { width = 320; height = 200; } else { width = 160; height = 100; } dlinfo.images_per_screen = 4; break; default: fprintf(stderr, "%s: only large and medium formats are handled", myname); exit(1); break; } /* * Get title and author (if any). i don't know what this is used * for... */ dlinfo.title[20] = dlinfo.author[20] = 0; for (i = 0; i < 20; i++) { dlinfo.title[i] = fgetc(fp) ^ 255; if ((unsigned char)dlinfo.title[i] == 255) dlinfo.title[i] = 0; } for (i = 0; i < 20; i++) { if (dlinfo.version == 2) { dlinfo.author[i] = fgetc(fp) ^ 255; if ((unsigned char)dlinfo.author[i] == 255) dlinfo.author[i] = 0; } else dlinfo.author[i] = 0; } /* * Read number of screens and commands. */ dlinfo.num_screen = fgetc(fp); dlinfo.num_command = fgetc(fp); /* * Display what we know so far. */ nframes = dlinfo.num_screen * dlinfo.images_per_screen; ncommands = dlinfo.num_command; if (verbose) { printf("%s is a %s sized version %d .DL file.\n", filename, (dlinfo.format == 0 ? "large" : "medium"), dlinfo.version); printf("It contains %d images (num_screen=%d * images_per_screen=%d)\n", dlinfo.num_screen * dlinfo.images_per_screen, dlinfo.num_screen, dlinfo.images_per_screen); printf("in a %d frame (num_command) loop.\n", dlinfo.num_command); if (dlinfo.format == 1 && zoomflag) { puts("Zooming images to 320x200."); } printf("Displaying animation at %d frames per second.\n",fps); } /* * do the color map */ if (verbose) printf("Reading colormap...\n"); colormap_setup(fp, dlinfo.version); /* * Allocate memory for the commands, the image data, etc */ if (verbose) printf ("Allocating memory:\n"); /* command list: */ if (verbose) printf (" command list (%d bytes)\n", dlinfo.num_command * sizeof(int)); if (!(cmd = (int *)malloc(dlinfo.num_command * sizeof(int)))) { fprintf(stderr, "%s: out of memory (commands)", myname); exit(1); } /* one screen (file): */ if (verbose) printf (" single screen from file (64000 bytes)\n"); if (NULL == (image_data = (unsigned char *)malloc(320 * 200))) { fprintf(stderr, "%s: not enough memory (image data).", myname); exit(1); } /* all frames: */ if(dlinfo.format == 0) { /* large */ if (verbose) printf (" raster list, large (%ld bytes)\n", (long)(320L * 200L * dlinfo.num_screen)); img = (unsigned char *)malloc(320 * 200 * dlinfo.num_screen); pimg_inc = 320 * 200; } else if (zoomflag) { /* medium->large */ if (verbose) printf (" raster list, zoom (%ld bytes)\n", (long)(320L * 200L * dlinfo.num_screen * dlinfo.images_per_screen)); img = (unsigned char *)malloc(320 * 200 * dlinfo.num_screen * dlinfo.images_per_screen); pimg_inc = 320 * 200; } else { /* medium */ if (verbose) printf (" raster list, medium (%ld bytes)\n", (long)(160L * 100L * dlinfo.num_screen * dlinfo.images_per_screen)); img = (unsigned char *)malloc(160 * 100 * dlinfo.num_screen * dlinfo.images_per_screen); pimg_inc = 160 * 100; } if (img == (unsigned char *) NULL) { fprintf(stderr, "%s: not enough memory (pimg).", myname); exit(1); } pimg = img; /* * Build the pixmaps for the animation. */ if (verbose) { printf("Building pixmaps, wait..."); fflush(stdout); } for (j = 0; j < dlinfo.num_screen; j++) { unsigned char *src; int row; int col; /* * Read one screen of data. */ fread(image_data, 1, 320 * 200, fp); /* * Each screen can hold several images. */ for (i = 0; i < dlinfo.images_per_screen; i++) { /* * Get a pointer to the beginning of this image. * Put the pixels in the img raster. We do zooming * by reading the same data several times. */ src = image_data + (i % 2) * 160 + (i / 2) * 100 * 320; for (row = 0; row < height; row++) { for (col = 0; col < width; col++) { /* * map raw data to colormap * intensity */ gray = pixels[*src] + ival; if (gray > 255) gray = 255; if (gray < 0) gray = 0; /* * poke in our raster */ pimg[width * row + col] = gray; src += (zoomflag) ? (col & 1) : 1; } if (dlinfo.format) { if (zoomflag) { src += (row & 1) ? 160 : -160; } else { src += 160; } } } /* * advance image pointer to next frame */ pimg += pimg_inc; } } if (verbose) printf("done.\n"); fflush(stdout); /* * Read the commands. */ if (verbose) printf("Number of commands is %d\n", dlinfo.num_command); for (i = 0; i < dlinfo.num_command; i++) { if (dlinfo.version == 2) { j = fgetc(fp); j += fgetc(fp) << 8; cmd[i] = j; } else { j = fgetc(fp); cmd[i] = (j % 10) - 1 + ((j / 10) - 1) * 4; } if (verbose) printf("command %3d: %d\n", i, cmd[i]); } if (verbose) fflush(stdout); /* * if last cmd is -ve, it contains the 'labelpos'. what is this? */ labelpos = 0; if (isneg16(cmd[dlinfo.num_command - 1])) { labelpos = (neg16(cmd[dlinfo.num_command - 1]) + 1); /* Correct? Why add 1 ?? */ dlinfo.num_command--; /* ignore that last command */ } /* * do it. first set delay per frame (milliseconds) */ frame_freq = 1000/fps; dl_flicker (img, nframes, width, height, beta, noise, do_flick, frame_freq, cmd, ncommands, verbose); exit (0); } /*------------------------------*/ /* colormap_setup */ /*------------------------------*/ void colormap_setup (FILE *fp, int version) { /* * Initialize the colormap. I use a private one for PseudoColor, * I was too tired to fiddle with allocating shared colors. */ unsigned char pal[768]; int i; /* * Is this the border colour? ignore this anyway... */ if (version == 2) { for (i = 0; i < 3; i++) fgetc(fp); } else fgetc(fp); /* * Here comes the colormap. 3 bytes per each of 256 colors. */ fread(pal, 1, 768, fp); /* * Set up for grayscale conversion on a monochrome display (NTSC * weights). flicker interprets 0 as black and 255 as white. * * TODO: consider histogram equalization here... */ for (i = 0; i < 256; i++) { pixels[i] = (((unsigned long)pal[3*i ] << 2) * 300) / 1000 + (((unsigned long)pal[3*i + 1] << 2) * 590) / 1000 + (((unsigned long)pal[3*i + 2] << 2) * 110) / 1000; } return; } /*------------------------------*/ /* usage */ /*------------------------------*/ void usage (int excode) { fprintf(stderr,"usage: %s [options] [file.dl]\n", myname); fprintf(stderr,"options:\n"); fprintf(stderr,"-v verbose\n"); fprintf(stderr,"-s single image (no flicker)\n"); fprintf(stderr,"-b beta for laplace filter (0..10)\n"); fprintf(stderr,"-n noise add random noise (0..255)\n"); fprintf(stderr,"-z zoom (enlarge to 320x200)\n"); fprintf(stderr,"-h help\n"); fprintf(stderr,"-i val add value to pixel intensity (-255..255)\n"); fprintf(stderr,"-r fps run at fps frames/second (default=25)\n"); exit (excode); }