/*
From: setlik@niktow.canisius.edu          Article 142 of alt.binaries.pictures.utilities
Article: 142 of alt.binaries.pictures.utilities
Path: bloom-picayune.mit.edu!mintaka.lcs.mit.edu!olivea!decwrl!sdd.hp.com!zaphod.mps.ohio-state.edu!ub!niktow!setlik
From: setlik@niktow.canisius.edu (Ebbhead)
Newsgroups: alt.binaries.pictures.utilities
Subject: dl to gl c-code
Message-ID: <1051@niktow.canisius.edu>
Date: 19 Jun 92 14:59:26 GMT
Organization: The Can
Lines: 411
*/

/*
 * dltogl.c -- convert .DL animations into .GL animations.
 *
 * usage: dltogl file.dl [file.gl]
 *
 * If no .gl file is specified, the images and control file will be
 * written to separate files.  The control file will always be "dl.txt",
 * the images "clpN.clp" and a palette file called "palette.pic".
 *
 * Author:
 *	George Phillips
 *	<phillips@cs.ubc.ca>
 */

#include <stdio.h>
#ifdef __TURBOC__
#include <alloc.h>
#else
extern char* malloc();
#endif

#define FOW	"wb"

FILE*	gl;
int		gl_fileno;

FILE* file_open();
int file_close();

#define isneg16(x)	((x) & 0x8000)
#define neg16(x)	((~(x) + 1) & 0x7fff)

main(argc, argv)
int		argc;
char*	argv[];
{
	unsigned int i, j;
	FILE* fp;
	int num_scrn;
	int ctl_len;
	int ch;
	int format;
	static char title[21];
	static char author[21];
	static unsigned char pal[256*3];
	unsigned char* screen;
	static unsigned char halfscreen[160*100];
	static char fname[32];
	int picnum;
	int images_per_screen;
	FILE* ctl;
	int fx, fy;
	int* cmd;
	int labelpos;
	int cmdnum;

	if (argc != 2 && argc != 3)
		die("usage: dltogl file.dl [file.gl]");

	if (!(fp = fopen(argv[1], "rb"))) {
		fprintf(stderr, "dltogl: can't open %s\n", argv[1]);
		exit(1);
	}

	gl = 0;
	gl_fileno = 0;
	if (argc == 3 && !(gl = fopen(argv[2], FOW))) {
		fprintf(stderr, "dltogl: can't open %s for writing\n", argv[2]);
		exit(1);
	}

	if (fgetc(fp) != 2)
		die("dltogl: only version 2 files can be handled");

	switch (format = fgetc(fp)) {
	case 0:
		fx = fy = 0;
		images_per_screen = 1;
		break;
	case 1:
		fx = 80;
		fy = 50;
		images_per_screen = 4;
		break;
	default:
		die("dltogl: only large and medium formats are handled");
		break;
	}

	title[20] = author[20] = 0;
	for (i = 0; i < 20; i++)
		title[i] = fgetc(fp) ^ 255;

	for (i = 0; i < 20; i++)
		author[i] = fgetc(fp) ^ 255;

	for (i = 0; i < 20; i++) {
		if ((unsigned char)title[i] == 255) title[i] = 0;
		if ((unsigned char)author[i] == 255) author[i] = 0;
	}

	num_scrn = fgetc(fp);
	ctl_len = fgetc(fp);

	if (!(cmd = (int*)malloc(ctl_len * sizeof(int))))
		die("dltogl: out of memory");

	gl_numfiles(num_scrn * images_per_screen + 1 + 1);

	/* mebbe this is the border colour? */
	for (i = 0; i < 3; i++)
		fgetc(fp);

	for (i = 0; i < 256; i++) {
		pal[i*3] = fgetc(fp);
		pal[i*3+1] = fgetc(fp);
		pal[i*3+2] = fgetc(fp);
	}

	if (!(screen = malloc(320 * 200)))
		die("dltogl: not enough memory.");

	memset(screen, 0, 320 * 200);
	writepic(screen, 320, 200, "palette.pic", pal);

	picnum = 0;
	for (j = 0; j < num_scrn; j++) {
		fread(screen, 320 * 200, 1, fp);
		switch (format) {
		case 0: /* large */
			sprintf(fname, "clp%d.clp", picnum++);
			writepic(screen, 320, 200, fname, (unsigned char*)0);
			break;
		case 1: /* medium */
			for (i = 0; i < 4; i++) {
				unsigned char*	src;
				unsigned char*	dst;
				int				row;
				int				col;

				sprintf(fname, "clp%d.clp", picnum++);
				src = screen + (i % 2) * 160 + (i / 2) * 100 * 320;
				dst = halfscreen;
				for (row = 0; row < 100; row++) {
					for (col = 0; col < 160; col++)
						*dst++ = *src++;
					src += 160;
				}
				writepic(halfscreen, 160, 100, fname, (unsigned char*)0);
			}
		}
	}

	ctl = file_open("dl.txt", FOW);

	fprintf(ctl, "; This GL file was converted from DL format by dltogl\r\n");
	fprintf(ctl, "; Title:  %s\r\n", title);
	fprintf(ctl, "; Author: %s\r\n", author);
	/* could print all the other keeno information */

	fprintf(ctl, "video l\r\n");
	fprintf(ctl, "pload palette,1\r\n");
	fprintf(ctl, "palette 1\r\n");
	fprintf(ctl, "pfree 1\r\n");
	for (i = 0; i < num_scrn * images_per_screen; i++)
		fprintf(ctl, "cload clp%d,%d\r\n", i, i + 1);

	for (i = 0; i < ctl_len; i++) {
		j = fgetc(fp);
		j += fgetc(fp) << 8;
		cmd[i] = j;
	}

	labelpos = 0;
	if (isneg16(cmd[ctl_len - 1])) {
		labelpos = neg16(cmd[ctl_len - 1]) + 1;
		ctl_len--;	/* ignore that last command */
	}

	for (i = 0, cmdnum = 0; i < ctl_len; i++, cmdnum++) {
		if (cmdnum == labelpos)
			fprintf(ctl, "forever:\r\n");
		if (isneg16(cmd[i])) {
			i++;
			fprintf(ctl, "waitkey %d\r\n", cmd[i]);
		}
		else
			fprintf(ctl, "putup %d,%d,%d,10\r\n", fx, fy, cmd[i] + 1);
	}
	fprintf(ctl, "goto forever\r\n");
	fputc(26, ctl);
	file_close(ctl);

	fclose(fp);

	if (gl)
		fclose(gl);

	exit(0);
}

die(s)char*s;{fprintf(stderr,"%s\n",s);exit(1);}

#define BLOCKSIZE	(8192)

writepic(pixel, width, height, filename, cmap)
unsigned char* pixel;
int	width;
int	height;
char* filename;
unsigned char* cmap;
{
	FILE*	fp;
	unsigned int i;
	static unsigned char buf[BLOCKSIZE];
	unsigned char* p;
	int row, col;

	fp = file_open(filename, FOW);

	/* write header */
	writeshort(fp, 0x1234);	/* magic number */
	writeshort(fp, width);
	writeshort(fp, height);
	writeshort(fp, 0);
	writeshort(fp, 0);
	fputc(8, fp);						/* bits per pixel */
	fputc(0xff, fp);					/* byte here is always 255 */
	fputc('L', fp);						/* video mode */
	if (cmap) {
		writeshort(fp, 4);		/* extra information descriptor */
		writeshort(fp, 768);	/* extra information length */
		fwrite(cmap, 768, 1, fp);
	}
	else {
		writeshort(fp, 0);
		writeshort(fp, 0);
	}

	/* number of packed blocks in file */
	writeshort(fp, ((long)width * height + BLOCKSIZE - 1) / BLOCKSIZE);

	i = 0;
	for (row = height - 1; row >= 0; row--) {
		p = pixel + row * width;
		for (col = 0; col < width; col++) {
			buf[i++] = *p++;
			if (i == BLOCKSIZE) {
				outpackblock(fp, buf, i);
				i = 0;
			}
		}
	}
	if (i > 0)
		outpackblock(fp, buf, i);

	file_close(fp);
}

outpackblock(fp, buf, len)
FILE*	fp;
char*	buf;
int	len;
{
	static char	packbuf[BLOCKSIZE * 4 - 1];	/* overkill */
	int	packlen;

	packlen = packblock(buf, packbuf, len);
	fwrite(packbuf, packlen, 1, fp);
}

packblock(src, dest, len)
char*	src;
char*	dest;
int		len;
{
	unsigned char*	s;
	unsigned char*	r;
	unsigned char*	d;
	static int	overhead[256];
	int	i;
	int	esc;
	int	escpresent;
	int	minover;
	int	packlen;

	for (i = 0; i < 256; i++)
		overhead[i] = 0;

	/* do first pass to find optimal esc byte */
	for (s = src; s < src + len; s = r) {
		for (r = s; *r == *s && r < src + len; r++)
			;
		if (r - s < 4)
			overhead[*s]++;
	}

	minover = len + 1;
	for (i = 0; i < 256; i++) {
		if (overhead[i] < minover) {
			minover = overhead[i];
			esc = i;
		}
	}
	escpresent = overhead[esc] == 0;

	/* now run-length encode on the second pass */

	d = dest + 5;
	for (s = src; s < src + len; s = r) {
		for (r = s; *r == *s && r < src + len; r++)
			;
		if (r - s < 4 && (!escpresent || *s != esc)) {
			while (s < r)
				*d++ = *s++;
		}
		else {
			if (r - s > 255) {
				*d++ = esc;
				*d++ = 0;
				*d++ = (r - s) & 0xff;
				*d++ = ((r - s) >> 8) & 0xff;
				*d++ = *s++;
			}
			else {
				*d++ = esc;
				*d++ = r - s;
				*d++ = *s++;
			}
		}
	}

	packlen = d - dest;

	/* fill in the block header */

	*dest++ = packlen & 0xff;			/* packed block size */
	*dest++ = ((packlen) >> 8) & 0xff;
	*dest++ = len & 0xff;
	*dest++ = (len >> 8) & 0xff;		/* unpacked block size */
	*dest++ = esc;						/* escape byte */

	return packlen;
}

writeshort(fp, s)
FILE*	fp;
int		s;
{
	fputc(s & 255, fp);
	fputc((s >> 8) & 255, fp);
}

writelong(fp, l)
FILE*	fp;
long	l;
{
	fputc(l & 255, fp);
	fputc((l >> 8) & 255, fp);
	fputc((l >> 16) & 255, fp);
	fputc((l >> 24) & 255, fp);
}

long gl_eof;
long gl_filestart;

gl_numfiles(n)
int	n;
{
	if (gl) {
		fseek(gl, 0, 0);
		writeshort(gl, n * 17);
		gl_eof = 2 + n * 17;
	}
}

FILE* file_open(name, mode)
char*	name;
char*	mode;
{
	FILE*	fp;
	char	fname[14];

	if (!gl) {
		if (!(fp = fopen(name, mode))) {
			fprintf(stderr, "dltogl: can't open %s\n", name);
			exit(1);
		}
		return fp;
	}

	fseek(gl, 2 + gl_fileno++ * 17, 0);
	writelong(gl, gl_eof);
	memset(fname, 0, 13);
	strcpy(fname, name);
	fwrite(fname, 13, 1, gl);
	fseek(gl, gl_filestart = gl_eof + 4, 0);
	return gl;
}

int file_close(fp)
FILE*	fp;
{
	if (!gl)
		return fclose(fp);

	gl_eof = ftell(gl);
	fseek(gl, gl_filestart - 4, 0);
	writelong(gl, gl_eof - gl_filestart);
}
