[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Screendump to MacPaint file for MiNT 1.10 + Psigintr



Well, I needed something to dump a screen to a MacPaint file, and I couldn't
find anything like that, let alone working under MiNT, thus this program.
The screen rotation code is pretty slow; I'm working on a more efficient one
but it works, so what the heck.

Hope someone else finds this useful...  -- Howard

/*
 * scrdump - Dump a monochrome screen in MacPaint format. Requires MiNT 1.10
 * plus Psigintr extension. I wrote this program because I've seen no other
 * code that will dump a screen to a file when running under MiNT.
 *
 * The program doesn't put itself into the background, but it ought to.
 * Dump files are named "ScreenXX.MAC" with two hex digits "XX". The program
 * exits after dumping 256 images. If the environment variable SCRDUMPS exists
 * and is set to a GEMDOS-format pathname, dumps will be created in that
 * directory, otherwise they will be in the current working directory.
 *
 * The MacPaint format isn't exactly the greatest format in the world. It's
 * a fixed size, 576 horizontal by 720 vertical. The only reason I used it
 * is because I needed to get some screen dumps to a doc-writer who was using
 * a Mac, and this is the simplest Mac format I had docs for. To get a better
 * fit, I rotate the ST screen 90 degrees before dumping it to disk. For
 * screens larger than 720x576, only the upper left corner gets dumped.
 *
 * Not the best-written stuff in the world, but it works...
 *
 *  -- Howard Chu, howard@lloyd.com	4-5-94
 *	(also at hyc@hanauma.jpl.nasa.gov, but phasing that out.)
 */

#include <mintbind.h>
#include <unistd.h>
#include <signal.h>
#include <linea.h>

int quit;

void sigit (int sig) {
	if (sig != SIGHUP)
		quit = 1;
}

/*
 * Once again, a strange problem - how do you get a signal from an interrupt-
 * time routine into a MiNT process. Using Psigintr directly doesn't work here
 * because the ALT-Help vector isn't at a long-word aligned address, and it's
 * invoked as a subroutine, not an exception. Perhaps Psigintr should be
 * changed to take an address instead of a vector number, with another argument
 * telling whether to return with RTE or RTS... ?
 *
 * Anyway, my solution here is to set the ALT-Help vector to point to a
 * routine that invokes an unused trap. Psigintr is called with that trap
 * vector, and so the desired signal gets delivered... What a kludge.
 */

#define Prt_cnt	*(short *)0x4eeL
#define	Scr_dump	*(long *)0x502L
#define	TRAP0VEC	0x20

void trapper () {
	if (Prt_cnt == 0)
		Prt_cnt = -1;
	__asm__("trap #0");
}

long oldprt;

void installer () {
	oldprt = Scr_dump;
	Scr_dump = (long)trapper;
}

void remover() {
	Scr_dump = oldprt;
}
		
const char digx[]="0123456789ABCDEF";
char file[]="Screen00.MAC";

/* MacPaint dimensions */

#define	M_X_MAX	576
#define	M_Y_MAX	720
#define	MAC_BUF	((M_X_MAX*M_Y_MAX>>3)+512)

main() {
	int i, j;
	int snum;
	int xmax, ymax;		/* max dimension, unrotated */
	int xlen;

	int fd;
	char *scr;
	char *wd, *pbuf;
	char *pt1, *pt2, *pt3, *pt4;
	char c, m1, m2;

	/* Go to specified dump directory */

	wd = (char *)getenv("SCRDUMPS");
	if (wd) {
		if (wd[1] == ':') {
			Dsetdrv((wd[0] & 0x1f)-1);
			wd += 2;
		}
		Dsetpath(wd);
	}
		
	scr = (char *)Logbase();

	/* Yeah, I know Line-A isn't supposed to be used any more, but it
         * still works on TT and Falcon, and there's no where else to find
	 * the Bytes_Per_Line value...
	 */

	linea0();
	xmax = V_X_MAX;
	if (xmax > M_Y_MAX)
		xmax = M_Y_MAX;
	ymax = V_Y_MAX;
	if (ymax > M_X_MAX)
		ymax = M_X_MAX;
	xlen = V_BYTES_LIN;

	wd = malloc(MAC_BUF);			/* MacPaint rez + header */
	bzero(wd, MAC_BUF);			/* zero the buffer */
	wd += 512;				/* Skip over the header */
	pbuf = malloc((ymax>>3)+1);		/* 1 PackBits line */

#if BORDERS==1
	/* Draw 2-pixel borders if image is smaller than MacPaint size */

	if (ymax < M_X_MAX) {
	    pt1 = wd + (ymax>>3);
	    j = xmax+2;
	    if (j > M_Y_MAX) j = M_Y_MAX;
	    for (i=0; i<j; i++) {
		*pt1 = 0xc0;
		pt1 += (M_X_MAX>>3);
	    }
	}

	if (xmax < M_Y_MAX-1) {
	    pt1 = wd + xmax*(M_X_MAX>>3);
	    for (i=0; i<ymax>>3; i++)
		*pt1++ = 0xff;
	    pt1 += (M_X_MAX-ymax) >> 3;
	    for (i=0; i<ymax>>3; i++)
		*pt1++ = 0xff;
	}
#endif

	/* Use trap 0 vector to signal us */

	signal(SIGHUP, sigit);
	signal(SIGINT, sigit);
	signal(SIGQUIT, sigit);
	signal(SIGTERM, sigit);
	
	Psigintr(TRAP0VEC, SIGHUP);
	Supexec(installer);

	for(snum=0;snum<256;snum++) {

		/* Set file name */

		file[7] = digx[snum & 0x0f];
		file[6] = digx[snum >> 4];

		/* Wait for ALT-Help signal */

		Pause();
		if (quit)
			break;

		/* Open output file, write header */

		fd = Fcreate(file, 0);
		if (fd < 0)
			continue;

		Fwrite(fd, 512, wd-512);

		/* Rotate image 90 degrees */

		pt1=scr + (xmax>>3)-1;	/* Far right src column */
		pt2=wd + ((M_X_MAX*(xmax-1)+ymax)>>3)-1;
					/* lower right corner */
		for (i=0, m1=1; i<xmax; i++) {
		    pt3 = pt1;	/* input */
		    m2 = 1;
		    for (j=0, c=0; j<ymax; j++) {
			if (*pt3 & m1)
			   c |= m2;
			pt3 += xlen;
			if (m2 < 0) {
			   m2 = 1;
			   *pt2-- = c;
			   c = 0;
			} else {
			   m2 += m2;
			}
		
		    }
		    pt2 -= ((M_X_MAX-ymax)>>3);
		    if (m1 < 0) {		/* signed char */
			m1 = 1;
			pt1--;
		    } else {
			m1 += m1;
		    }
		}
		    
		/* Write output in PackBits format */

		pt1 = wd;
#if PACKBITS==1
		for (i=0; i<M_Y_MAX; i++) {	/* For each line */
		    m1 = 0;			/* No repeats */
		    m2 = *pt1+1;		/* Previous char */
		    pt3 = pt1; 		/* beginning of literal */
		    pt4 = 0;		/* beginning of run */
		    pt2 = pbuf;
		    for (j=0; j<M_X_MAX>>3; j++) {
			if (*pt1 == m2)	{
			    if (pt4) {		/* Accumulate repeats */
				m1++;
			    } else if (j<((M_X_MAX>>3)-1) && pt1[1] == m2) {
				pt4 = pt1-1;	/* Initialize repeats */
				m1 = 3;
				++j;
				++pt1;
				if (pt3 < pt4) {	/* flush literals */
					*pt2++ = pt4-pt3-1;
					for (;pt3 < pt4;)
					    *pt2++ = *pt3++;
				}
			    }
			    pt1++;
			} else {
			    if (m1) {		/* End of run, how many? */
				--m1;
				*pt2++ = -m1; 
				*pt2++ = m2;
				pt3 = pt1;
				pt4 = 0;
				m1 = 0;
			    }
			    m2 = *pt1++;	/* set prev char */
			}
		    }

		/* Dump end of line */

		    if (m1) {			/* finish repeats */
			--m1;
			*pt2++ = -m1;
			*pt2++ = m2;
		    } else if (pt3 < pt1) {	/* finish literals */
			*pt2++ = pt1-pt3-1;
			for(;pt3 < pt1;)
			    *pt2++ = *pt3++;
		    }
		    Fwrite(fd, pt2 - pbuf, pbuf);
		}
#else
		/* Dump it straight, no repeat-suppression */

		c = (M_X_MAX>>3)-1;
		for (i=0; i<M_Y_MAX; i++) {
		    Fwrite(fd, 1, &c);
		    Fwrite(fd, c+1, pt1);
		    pt1 += c+1;
		}
#endif					
		Fclose(fd);
	}
	Supexec(remover);
}