home *** CD-ROM | disk | FTP | other *** search
- /*
- xflick - Ron Schnell, March, 1991
-
- This code is provided as is, with no warrantees, expressed
- or implied. I believe this code to be free of encumbrance,
- and offer it to the public domain. I ask, however, that
- this paragraph and my name be retained in any modified
- versions of the file you may make, and that you notify me
- of any improvements you make to the code.
-
- Ron Schnell (ronnie@sos.com)
-
- */
-
- /*
- The following changes are from Michael Pall
- (pall@rz.uni-karlsruhe.de) Mar 25-28 1991:
-
- Lots of bugfixes and changes to the structure of the files.
- The file is interpreted before we display it.
- Moved the interpretation part to read.c.
- We use Pixmaps and/or XImages.
- Added interactive input to change the speed/single step.
- */
-
- /*
- The following extensions are from Klaus Ehrenfried
- (klaus@spock.es.go.dlr.de) Oct 23-24 1992:
-
- Add handling of FLI_DELTA and FLI_256_COLOR chunks.
- Recognize magic number FLC_MAGIC = 0xaf12 for newer
- flic files.
- */
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/signal.h>
- #include <sys/time.h>
- #include "xflick.h"
- #include <X11/Xos.h>
- #include <X11/Xlib.h>
- #include <X11/Xutil.h>
- #include <X11/Xatom.h>
-
-
- int verbose = 0;
-
- static int timeout; /* Necessary global for itimer waiting */
- static int usecs,rsecs; /* ditto */
-
- static Display *display; /* The display connection */
- static int screen; /* The default screen */
- static Window rootw, window; /* Root window and our own window */
- static XImage *img; /* The image for the current frame */
- static GC gc, blackgc; /* Graphics contexts */
- static Colormap cmap; /* The colormap for our window */
- static XEvent event; /* Events for our window */
-
- static flag_img = 0; /* Use XImages instead of Pixmaps */
- static flag_noint = 0; /* Don't interpret file first */
-
- static int fdelay; /* Frame delay */
- static int wwidth, wheight; /* Width and height of the window */
-
- /* The structure to hold the elements of the interpreted display list */
-
- struct disp_list
- {
- int disp_type;
- int disp_frame;
- Pixmap disp_pix;
- XImage *disp_img;
- XColor *disp_cols;
- int disp_numcol;
- int disp_width, disp_height;
- int disp_destx, disp_desty;
- struct disp_list *disp_next;
- };
-
- static struct disp_list disp_root; /* The start of the display list */
- static struct disp_list *disp_cur; /* The current position */
-
- extern void interpret_fli();
-
- /* Function which gets called by the signal handler when SIGALRM
- occurs */
-
- static
- bong()
- {
- timeout = True;
- }
-
-
- /* Convert the frame delay to microseconds/seconds */
-
- static void
- convert_fdelay()
- {
- usecs = (fdelay % 70) * 14285;
- rsecs = fdelay / 70;
- }
-
- /* Print an error message and exit */
-
- void
- xferror(str)
- char *str;
- {
- (void) fprintf(stderr, "%s\n", str);
- exit(-1);
- }
-
- /* Print a usage message and exit */
-
- static void
- usage()
- {
- (void) fprintf(stderr,
- "Usage: xflick [-v] [-r<count>] [-d<delay>] [-i] [-n] file\n");
- (void) fprintf(stderr, " -v Verbose Debugging info\n\
- -r<count> Repeat count times\n\
- -d<delay> Delay between frames in 1/70s\n\
- -i Use XImages instead of Pixmaps (slower but some servers need it)\n\
- -n Don't interpret file before display \
- (slower but uses less memory)\n");
- exit(0);
- }
-
- /* Check for pending KeyPress events and process them */
-
- static void
- check_key()
- {
- static int stepflag = 0; /* Default: singlestep is off */
-
- char kbuf; /* The buffer to hold the translation */
- int onestep = stepflag; /* 1 if we should loop waiting for a step */
-
- /* We poll the event Queue and block only in singlestep mode */
-
- while (onestep || QLength(display) > 0)
- {
- /* Get the event (blocks until event received) */
-
- XNextEvent(display, &event);
-
- /* Is it a KeyPress event and is it for our window (just in case)? */
-
- if (event.type == KeyPress && ((XKeyEvent *)&event)->window == window)
- {
- /* Translate the event to a string */
- if (XLookupString((XKeyEvent *)&event, &kbuf, 1, NULL, NULL) != 1)
- continue;
-
- /* Uppercase to lowercase mapping. We don't use ctype.h since
- it's only used here */
-
- if (kbuf>='A' && kbuf<='Z')
- kbuf += 0x20;
-
- switch (kbuf)
- {
- /* Minus: Slow down */
- case '-':
- fdelay++;
- convert_fdelay();
- break;
- /* Plus: Speed up */
- case '+':
- if (fdelay)
- fdelay--;
- convert_fdelay();
- break;
- /* Space: Single step */
- case ' ':
- stepflag = 1;
- onestep = 0;
- break;
- /* Return: Continue animation */
- case 0x0d:
- stepflag = 0;
- onestep = 0;
- break;
- /* 'q': Quit */
- case 'q':
- exit(0);
- break;
- }
- }
- }
- }
-
-
- /* Function to display the interpretation immediately */
-
- static void
- func_disp(ftype, frame, buf, srcx, srcy, destx, desty, swidth, sheight)
- int ftype;
- int frame;
- unsigned char *buf;
- int srcx, srcy;
- int destx, desty;
- int swidth, sheight;
- {
- static int colchange=0; /* Colormap has changed */
-
- struct itimerval iclock; /* For timeout setting */
- XColor color;
-
- switch (ftype) {
- case FLI_COPY:
- case FLI_LC:
- case FLI_DELTA:
- case FLI_BRUN:
- img->data = (char *)buf;
- XPutImage(display, window, gc, img, srcx, srcy, destx, desty,
- swidth, sheight);
- break;
- case FLI_BLACK:
- XFillRectangle(display, window, blackgc, destx, desty,
- swidth, sheight);
- break;
- case FLI_COLOR:
- while(srcy--)
- {
- color.red = ((*(buf++) & 0x3f) << 2) << 8;
- color.green = ((*(buf++) & 0x3f) << 2) << 8;
- color.blue = ((*(buf++) & 0x3f) << 2) << 8;
- color.pixel = srcx++;
- color.flags = DoRed|DoGreen|DoBlue;
- XStoreColor(display, cmap, &color);
- }
- colchange = 1;
- break;
- case FLI_256_COLOR:
- while(srcy--)
- {
- color.red = ((*(buf++) & 0xff)) << 8;
- color.green = ((*(buf++) & 0xff)) << 8;
- color.blue = ((*(buf++) & 0xff)) << 8;
- color.pixel = srcx++;
- color.flags = DoRed|DoGreen|DoBlue;
- XStoreColor(display, cmap, &color);
- }
- colchange = 1;
- break;
- case FLI_SYNC:
- if (colchange)
- {
- XSetWindowColormap(display, window, cmap);
- colchange = 0;
- }
- XSync(display, 0);
-
- check_key();
-
- /* Do we have a delay between the frames? */
- if (usecs || rsecs)
- {
- timeout = False;
- signal(SIGALRM, bong);
- iclock.it_value.tv_sec = rsecs;
- iclock.it_value.tv_usec = usecs;
- iclock.it_interval.tv_sec = rsecs;
- iclock.it_interval.tv_usec = usecs;
- (void) setitimer(0, &iclock, 0);
-
- if (!timeout)
- (void) pause();
-
- iclock.it_value.tv_sec = 0;
- iclock.it_value.tv_usec = 0;
- iclock.it_interval.tv_sec = 0;
- iclock.it_interval.tv_usec = 0;
- (void) setitimer(0, &iclock, 0);
- }
- break;
- }
-
- }
-
- /* Store the interpretation */
-
- static void
- func_interp(ftype, frame, buf, srcx, srcy, destx, desty, swidth, sheight)
- int ftype; /* The type of this chunk */
- int frame; /* The number of this frame */
- unsigned char *buf; /* A pointer to the pixel/colormap data */
- int srcx, srcy; /* The upper left corner in the data array */
- int destx, desty; /* The upper left corner in the window */
- int swidth, sheight; /* The dimensions of the rectangle */
- {
- XColor *coltmp; /* Temporary storage for pointer to XColor struct */
- Pixmap pixtmp; /* Temporary storage for the Pixmap id */
-
- /* Allocate another element in the display list */
- disp_cur->disp_next = (struct disp_list *)malloc(sizeof(struct disp_list));
- disp_cur = disp_cur->disp_next;
-
- /* Clear the pointer to the next element so we find the end of the list */
- disp_cur->disp_next = (struct disp_list *)0;
-
- /* Copy info pertaining to all or most of the chunks */
- disp_cur->disp_type = ftype;
- disp_cur->disp_frame = frame;
- disp_cur->disp_width = swidth;
- disp_cur->disp_height = sheight;
- disp_cur->disp_destx = destx;
- disp_cur->disp_desty = desty;
-
- switch (ftype) {
- case FLI_COPY:
- case FLI_LC:
- case FLI_DELTA:
- case FLI_BRUN:
- img->data = (char *)buf;
-
- /* There's no reason to store the first frame in a Pixmap since it
- will be used only once. Also use XImages if we've been told so */
- if (frame==0 || flag_img)
- {
- disp_cur->disp_pix = (Pixmap)0; /* No Pixmap */
- disp_cur->disp_img = XSubImage(img, srcx, srcy, swidth, sheight);
- }
- else
- /* Otherwise we create a Pixmap and copy the changed rectangle to it */
- {
- pixtmp = XCreatePixmap(display, rootw, swidth, sheight, 8);
- if (!pixtmp)
- xferror("Cannot create Pixmap. Try command line switch -i.");
-
- XPutImage(display, pixtmp, gc, img, srcx, srcy, 0, 0,
- swidth, sheight);
- disp_cur->disp_pix = pixtmp;
- }
- break;
- case FLI_COLOR:
- /* Create an array of XColor to hold the colors. Specific to FLI_COLOR:
- srcx is the starting color index and srcy is the number of colors */
- coltmp = (XColor *)malloc(srcy * sizeof(XColor));
- disp_cur->disp_cols = coltmp;
- disp_cur->disp_numcol = srcy;
-
- /* Copy the changed colors to the XColor array */
- while(srcy--)
- {
- coltmp->red = ((*(buf++) & 0x3f) << 2) << 8;
- coltmp->green = ((*(buf++) & 0x3f) << 2) << 8;
- coltmp->blue = ((*(buf++) & 0x3f) << 2) << 8;
- coltmp->pixel = srcx++;
- coltmp->flags = DoRed|DoGreen|DoBlue;
- coltmp++;
- }
- break;
- case FLI_256_COLOR:
- /* Create an array of XColor to hold the colors. Specific to FLI_COLOR:
- srcx is the starting color index and srcy is the number of colors */
- coltmp = (XColor *)malloc(srcy * sizeof(XColor));
- disp_cur->disp_cols = coltmp;
- disp_cur->disp_numcol = srcy;
-
- /* Copy the changed colors to the XColor array */
- while(srcy--)
- {
- coltmp->red = ((*(buf++) & 0xff)) << 8;
- coltmp->green = ((*(buf++) & 0xff)) << 8;
- coltmp->blue = ((*(buf++) & 0xff)) << 8;
- coltmp->pixel = srcx++;
- coltmp->flags = DoRed|DoGreen|DoBlue;
- coltmp++;
- }
- break;
-
- /* FLI_BLACK and FLI_SYNC only need to be stored */
- case FLI_BLACK:
- case FLI_SYNC:
- break;
- }
-
- }
-
- /* Display the stored interpretation */
-
- static void
- display_interp(dc)
- struct disp_list *dc; /* The structure holding the info on the chunk */
- {
- static int colchange=0; /* Colormap has changed */
-
- struct itimerval iclock; /* For timeout setting */
- int swidth, sheight; /* Dimension of the changing rectangle */
- int destx, desty; /* Upper left corner of the rectangle */
-
- /* Copy some fields from the structure */
- swidth = dc->disp_width;
- sheight = dc->disp_height;
- destx = dc->disp_destx;
- desty = dc->disp_desty;
-
- switch (dc->disp_type) {
- case FLI_COPY:
- case FLI_LC:
- case FLI_DELTA:
- case FLI_BRUN:
- /* A Pixmap needs to be copied internally by the server */
- if (dc->disp_pix)
- {
- XCopyArea(display, dc->disp_pix, window, gc, 0, 0,
- swidth, sheight, destx, desty);
- }
- else
- /* XImages need to be transferred from the client */
- {
- XPutImage(display, window, gc, dc->disp_img, 0, 0, destx, desty,
- swidth, sheight);
- }
- break;
- case FLI_BLACK:
- /* Clear the whole rectangle */
- XFillRectangle(display, window, blackgc, destx, desty,
- swidth, sheight);
- break;
- case FLI_COLOR:
- case FLI_256_COLOR:
- /* Store the changed colors in the colormap and note that */
- XStoreColors(display, cmap, dc->disp_cols, dc->disp_numcol);
- colchange = 1;
- break;
- case FLI_SYNC:
- /* If the colors have changed we set the colormap for the window */
- if (colchange)
- {
- XSetWindowColormap(display, window, cmap);
- colchange = 0;
- }
- /* Keep things in sync */
- XSync(display, False);
-
- check_key();
-
- /* Do we have a delay between the frames? */
- if (usecs || rsecs)
- {
- timeout = False;
- signal(SIGALRM, bong);
- iclock.it_value.tv_sec = rsecs;
- iclock.it_value.tv_usec = usecs;
- iclock.it_interval.tv_sec = rsecs;
- iclock.it_interval.tv_usec = usecs;
- (void) setitimer(0, &iclock, 0);
-
- if (!timeout)
- (void) pause();
-
- iclock.it_value.tv_sec = 0;
- iclock.it_value.tv_usec = 0;
- iclock.it_interval.tv_sec = 0;
- iclock.it_interval.tv_usec = 0;
- (void) setitimer(0, &iclock, 0);
- }
- break;
- }
- }
-
-
- /* Draw a given string to the center of the window */
-
- static void
- text_center(str)
- char *str;
- {
- XFontStruct *fixedfont;
- GC fontgc;
- int w;
-
- /* Load the fixed width font */
-
- fixedfont = XLoadQueryFont(display, "fixed");
- if (fixedfont)
- {
- /* Create a GC to draw the font */
-
- fontgc = XCreateGC(display, rootw, 0, NULL);
- XCopyGC(display, gc, -1, fontgc);
- XSetBackground(display, fontgc, BlackPixel(display, screen));
- XSetForeground(display, fontgc, WhitePixel(display, screen));
- XSetFont(display, fontgc, fixedfont->fid);
-
- /* Determine the width of the string */
-
- w = XTextWidth(fixedfont, str, strlen(str));
- if (w > wwidth)
- w = wwidth;
-
- /* And draw the string */
-
- XDrawImageString(display, window, fontgc, (wwidth-w)/2,
- wheight/2, str, strlen(str));
-
- /* Free everything and show the text */
-
- XFreeGC(display, fontgc);
- XFreeFont(display, fixedfont);
- XFlush(display);
- }
- }
-
-
- main(argc, argv)
- char **argv;
- {
- int fd; /* For the main file descriptor */
- struct fli_header header; /* To hold the main header */
- unsigned char *data; /* Always has the current image data */
- int repeatcount; /* How many times to loop */
- unsigned char notfirst; /* Is this not the first time through? */
- char *fname; /* Pointer to filename */
-
- /* X stuff begins here */
-
- XSizeHints hints; /* Hints for window mapping */
- Visual *visual;
- int xloc, yloc;
-
-
- fdelay = -1;
- repeatcount = 10;
-
- while (--argc && argv[1][0] == '-')
- {
- argv++;
- switch (argv[0][1]) {
- case 'r':
- repeatcount = atol(&(argv[0][2]));
- break;
- case 'd':
- fdelay = atol(&(argv[0][2]));
- break;
- case 'n':
- flag_noint = 1;
- break;
- case 'i':
- flag_img = 1;
- break;
- case 'v':
- verbose = 1;
- break;
- default:
- usage();
- }
-
- }
-
- if (argc != 1)
- usage();
-
- fname = argv[1];
- fd = open(fname, 0);
- if (fd < 0)
- {
- (void) fprintf(stderr, "Error opening %s.\n", fname);
- perror("xflick");
- exit(1);
- }
-
- /* Read the main FLI header */
-
- read_flihead(fd, &header);
-
- if (((header.fhd_magic & 0x0000ffff) != FLI_MAGIC) &&
- ((header.fhd_magic & 0x0000ffff) != FLC_MAGIC))
- {
- (void) fprintf(stderr, "%s, not a .fli file.\n", fname);
- exit(0);
- }
-
- /* Get the width and height */
-
- wwidth = header.fhd_width;
- wheight = header.fhd_height;
- data = (unsigned char *)malloc(wwidth * wheight);
-
- /* The speed is stored in 1/70 seconds, convert to usecs */
-
- if (fdelay<0)
- fdelay = header.fhd_speed;
- convert_fdelay();
-
- display = XOpenDisplay(NULL);
- if (display == NULL)
- xferror("Cannot open display.");
-
- /* Create a wwidth x wheight window to show the flick */
-
- screen = DefaultScreen(display);
- visual = DefaultVisual(display, screen);
- rootw = RootWindow(display, screen);
-
- if (DisplayCells(display, screen) < 256)
- xferror("You do not have enough colors to run xflick.");
-
- xloc = (DisplayWidth(display, screen) - wwidth) / 2;
- yloc = (DisplayHeight(display, screen) - wheight) / 2;
-
- window = XCreateSimpleWindow(display, rootw, xloc, yloc, wwidth, wheight,
- CopyFromParent, CopyFromParent, BlackPixel(display, screen));
-
- /* Set size hints to disable resizing */
-
- hints.flags = (PSize | PMinSize | PMaxSize);
- hints.min_width = hints.max_width = hints.width = wwidth;
- hints.min_height = hints.max_height = hints.height = wheight;
-
- /* Set window and icon name, size hints and other properties */
-
- XSetStandardProperties(display, window, fname, fname, None,
- argv, argc, &hints);
-
- gc = DefaultGC(display, screen);
-
- /* Create a GC with a foreground pixel value of 0 for FLI_BLACK */
-
- blackgc = XCreateGC(display, rootw, 0, NULL);
- XCopyGC(display, gc, -1, blackgc);
- XSetForeground(display, blackgc, 0);
-
- /* Create a colormap and allocate all colors */
-
- cmap = XCreateColormap(display, rootw, visual, AllocAll);
-
- /* Catch Exposure events and KeyPress events */
-
- XSelectInput(display, window, ExposureMask | KeyPressMask);
-
- /* Now map our little window */
- XMapWindow(display, window);
-
- /* We wait for an exposure event, since any output to the window is
- lost if the window is not yet visible */
-
- do
- XNextEvent(display, &event);
- while (event.type != Expose);
-
- /* Now we are no longer interested in Exposure events */
-
- XSelectInput(display, window, KeyPressMask);
-
- /* Create the XImage to hold the current frame */
- img = XCreateImage(display, visual, 8, ZPixmap, 0,
- data, wwidth, wheight, 8, wwidth);
-
-
- notfirst = 0;
-
- /* Either interpret the file while displaying it */
-
- if (flag_noint)
- {
- while (repeatcount--) {
- interpret_fli(fd, &header, data, notfirst, func_disp);
- notfirst = 1;
- }
- }
-
- /* Or interpret everything first and display it afterwards */
-
- else
-
- {
- text_center("Please wait while loading the animation");
-
- /* Interpret it and store the results */
-
- disp_cur = &disp_root;
- interpret_fli(fd, &header, data, 0, func_interp);
-
- /* Now display the results */
-
- while (repeatcount--)
- {
- disp_cur = &disp_root;
- while (disp_cur->disp_next)
- {
- disp_cur = disp_cur->disp_next;
-
- /* Only display the first frame once */
-
- if (disp_cur->disp_frame || !notfirst)
- display_interp(disp_cur);
- }
- notfirst = 1;
- }
- }
-
- return 0;
- }
-
-