home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware 1 2 the Maxx
/
sw_1.zip
/
sw_1
/
VIEWERS
/
UNIXVIEW
/
XFLITAR.Z
/
XFLITAR
/
xflick.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-19
|
16KB
|
656 lines
/*
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.
*/
#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_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_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_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;
/* 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_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:
/* 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)
{
(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;
}