
/* This module converts the DOOM raw image format to PPM image format

	(PPM, mainly because I know its format)

*/

#include	<stdio.h>
#include	<assert.h>
#include	"doomdefs.h"
#include	"directory.h"


struct raw_header {
	two_byte width;			/* Picture width */
	two_byte height;		/* Picture height */
	two_byte l_offset;		/* Left offset from center (unused?) */
	two_byte t_offset;		/* Top offset from center (unused?) */
	};

struct color {
	unsigned char red;
	unsigned char green;
	unsigned char blue;
	} colormap[256];

/* The background color for the pictures */
struct color cyan = { 0, 255, 255 };

int load_colormap(int fd) {
	struct dir_entry entry;

	/* Set the fd to the start of the directory entries */
	if ( set_directory(fd) < 0 )
		return(-1);

	/* Now cycle through the entries, looking for PLAYMAP */
	if ( get_entry(fd, "PLAYPAL", &entry) < 0 )
		return(-1);

	/* Go to the entry and retrieve the first colormap (colormap 0) */
	if ( lseek(fd, entry.res_start, SEEK_SET) < 0 )
		return(-1);
	if (read(fd, (char *)&colormap, sizeof(colormap)) != sizeof(colormap))
		return(-1);

	return(0);
}

int convert_rawpic(int fd, char *name)
{
	struct dir_entry entry;
	struct raw_header header;
	struct color *matrix;
	four_byte *columns;
	unsigned char post_row, num_pixels, pixel;
	char outfile[BUFSIZ];
	FILE *output;
	int i, j, l, index;

	/* Load the default colormap first */
	if ( load_colormap(fd) < 0 ) {
		fprintf(stderr, "Couldn't load color map from doom.wad\n");
		return(-1);
	}

	/* Set the fd to the start of the directory entries */
	if ( set_directory(fd) < 0 ) {
		fprintf(stderr, "Can't find start of directories.\n");
		return(-1);
	}

	/* Now cycle through the entries, looking for the picture  */
	if ( get_entry(fd, name, &entry) < 0 ) {
		fprintf(stderr, "Couldn't find directory entry for %s\n", name);
		return(-1);
	}

	/* Go to the entry and retrieve the picture */
	if ( lseek(fd, entry.res_start, SEEK_SET) < 0 ) {
		perror("lseek()");
		return(-1);
	}
	if (read(fd, (char *)&header, sizeof(header)) != sizeof(header)) {
		perror("header read error");
		return(-1);
	}
	/* Print out the header for now */
	printf("Picture size: %dx%d  (left offset=%d, top offset=%d)\n", 
		header.width, header.height, header.l_offset, header.t_offset);

	/* Allocate memory for the picture */
	if ( (matrix=(struct color *)malloc(
		sizeof(struct color)*(header.width*header.height))) == NULL ) {
		perror("malloc(matrix)");
		return(-1);
	}
	if ( (columns=(four_byte *)malloc(header.width*4)) == NULL ) {
		perror("malloc(columns)");
		return(-1);
	}
	
	/* Set the default color to cyan */
	for ( i=0; i<header.height; ++i )
		for ( j=0; j<header.width; ++j )
			matrix[(i*header.width)+j] = cyan;

	/* Convert the raw picture format into the pixel matrix */
	/* Get all the columns pointers */
	if ( read(fd, (char *)columns, header.width*4) != (header.width*4) ) {
		perror("read(columns");
		return(-1);
	}
	/* I tried using the offsets in the header, but they didn't seem
	   to be relevant.  Thus, I ignore them.
	 */
	for ( i=0; i<header.width; ++i ) {
		/* Each column is stored as a series of posts */
		if ( lseek(fd, entry.res_start+columns[i], SEEK_SET) < 0 ) {
			perror("lseek(columns)");
			return(-1);
		}
		for ( ; ; ) {
			/* The first byte is the starting row of the post */
			if ( read(fd, &post_row, 1) != 1 ) {
				perror("read()");
				return(-1);
			}
			if ( post_row == 255 )  /* End of column marker */
				break;
			/* The second byte is the number of pixels in the post */
			if ( read(fd, &num_pixels, 1) != 1 ) {
				perror("read()");
				return(-1);
			}
			/* Skip first and last pixel bytes */
			(void) read(fd, &pixel, 1);
			for ( j=0; j<num_pixels; ++j ) {
				if ( read(fd, &pixel, 1) != 1 ) {
					perror("read()");
					return(-1);
				}
				index=((post_row*header.width)+i);
				assert(index > 0);
				matrix[index] = colormap[pixel];
				++post_row;
			}
			(void) read(fd, &pixel, 1);
		}
	}

	/* Make sure we can write the output file */
	sprintf(outfile, "%s.ppm", name);
	if ( (output=fopen(outfile, "w")) == NULL ) {
		fprintf(stderr, "Can't open %s for writing.\n", outfile);
		return(-1);
	}
	/* Write the output file */
	fprintf(output, "P3\n");	/* PPM Magic cookie */
	fprintf(output, "# %s\n", outfile);
	fprintf(output, "%d %d\n", header.width, header.height);
	fprintf(output, "255\n");	/* The maximum color value */
	/* Now the matrix itself */
	for ( i=0; i<header.height; ++i ) {
		fprintf(output, "# row %d\n", i);
		for ( j=0, l=0; j<header.width; ++j ) {
			index = ((i*header.width)+j);
			sprintf(outfile, "%d %d %d  ", matrix[index].red, 
				matrix[index].green, matrix[index].blue);

			/* The line can be no longer than 70 chars */
			l += strlen(outfile);
			if ( l > 70 ) {
				fprintf(output, "\n");
				l = strlen(outfile);
			}
			fprintf(output, "%s", outfile);
		}
		fprintf(output, "\n");
	}
	fclose(output);

	/* Free malloc()'d data here.  It is not freed on errors */
	(void) free(matrix);
	(void) free(columns);

	/* Done! */
	return(0);
}
