Title		:RAQ
filename	:raq.zp
Version	        :1.00
Date		:17th Jan 1997
Author	        :Ian Waugh
Email		:ian.waugh@virgin.net

Intro
-----
RAQ is a noddy little win 32 console App that checks the header and body information in a .PCX graphics
file. If you pass it a second parameter it copies the first file into the second, adjusting the PCX 
header to X and Y coords 0,0. The primary purpose of this thing was to find out why Quake 2 skins saved
as valid .PCX files in Corel Photopaint 7 didn't work properly in Quake 2, and fix them. PaintShopPro4 
saves them in the correct format so this could be used as a conversion tool, but its a bit of a bind 
use a bug application like that that when you want to is a quick conversion( raq takes about a second )
so you can view your skin though quake II or a model viewer like md2.


Quake II Skin PCX Files
-----------------------
As far as I can tell Quake II skins are valid type 5 8 bit PCX files, but unlike quakeworld, quake II 
is seems to be very fussy about the start coordinates of the image. Theses coordinates, along with
other stuff ( widths, bits per pixel etc ) is held in the first 128 bytes of a PCX file. When 
PhotoPaint 7 saves a PCX files it saves the image at coords 1,1 . Images saved at 1,1 look very 
distorted when used in quake II ( or the MD2 model viewer ). Another odd fact about the standard Quake 
II skins is that although PCX files are usually compressed with a very simple and fast compression 
system called run length encoding. The standard skins supplied on the Q2 CD haven't been compressed 
properly, so average about 50K in length. Saving one of these in Corel PhotoPaint 7 ( or PaintShopPro 
4 ) reduces the size of the image to about 30K, compressing it properly. But Quake II will still load 
fully compressed .PCX files (with the correct start coords ) and work fine. So why didn't ID compress 
them ? 


Installation
------------
Just plop the raq.exe anywhere, the directory you work on your quake II skins is probably best 
(e.g. c:\Quake2\baseq2\players\female ).


Usage
------
Usage : raq  InputFile  [OutpufFile]

Raq accepts 1 or two parameters, the first parameter is the source PCX file, RAQ just scans through 
this and prints out various details about the PCX file. Passing it a second parameter ( must be 
different from the first )causes it to copy the first file into the second, nudging the X,Y coords
so the second PCX file will work as s skin in quake 2
It only takes about a second to run.
		
RAQ is a console app, it takes parameters and generates file and text output, you can run it in a DOS 
box, but it is probably easier to create a .BAT file for the skin you are working on and just double 
click on that from Windows Explorer.
e.g. of 1 line Batch file.
raq gunmetalb.pcx gunmetal.pcx

Remember for a skin to work in quake II is has got to be in the Male or Female directory, and have the
main image and  image's icon ( the ..._i.pcx ) file with it. These Icons are 32x32 images, in the 
same format as the skins, so if you draw or modify one in PhotoPaint you will have to Raq that to.
My current skin gunmetal.pcx and gunmetal_i.pcx is included in the zip, if you like please plonk
them in your quake2\baseq2\players\female directory, so you can see me (GUNDAM ,usually play on BT's
wireplay servers) when I come to frag you.



Copyright and Distribution Permissions
--------------------------------------
DISCLAIMER:  Raq is unsupported, and I'm not responsible for it doing any thing nasty to you or
your PC ( like anything this mickey mouse could ). Apart from that, do what you like with it. 



Source
------
Source code is included so people unsure about unsolicited little programs downloaded from the net
can compile (I used VC++ 5.0 ) there own version. Its nothing very clever, just straight C, most of 
the PCX format details came from a book (Secrets of the game programming Guru's) and its over long and 
Non-optimal. but hey what the hell its only 32k anyway and takes a second to run as it stands.



/*             	  RAQ 
      PCX file nudger for use with Quake II skins 
   	    RAQ doesn't stand for anything 
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef  struct RGB_colour_typ
{
	unsigned char red;
	unsigned char green;
	unsigned char blue;

} RGB_colour, *RGB_colour_ptr;



/* Use 16 bit integers, ( shorts in VC++ 5.0 ) this structure must be 128 bytes long */
typedef struct pcx_header_type
{
	char  manufacturer;
	char  version;

	char  encoding;

	char  bits_per_pixel;
	short x,y;

	short width,height;    
	short horz_res;

	short vert_res;

	char  ega_palette[48];

	char  reserved;

	char  num_colour_planes;

	short bytes_per_line;

	short palette_type;

	char  padding[58];

}pcx_header, *pcx_header_ptr;




typedef struct pcx_picture_typ
{
	pcx_header header;
	RGB_colour	palette[256];
	char *buffer;
} pcx_picture, *pcx_picture_ptr;


int PCX_convert( char * ,char * );

int main( int argc , char *argv[] )
{
	char * psInFileName, *psOutFileName;

	if ( argc < 2 || argc > 3 ) 
	{
		printf( "Usage : raq  InputFile  [OutpufFile]\n" );
		exit(0);
	}
	
	psInFileName  = argv[1];
	if ( argc == 3 )
		psOutFileName = argv[2];
	else
		psOutFileName = "\0";

	if ( !strcmp( psInFileName,psOutFileName ) )
	{
		printf( "raq error : InputFile and OutpufFile must be different\n" );
		exit(0);
	}

	if ( !PCX_convert( psInFileName,psOutFileName ) )
		exit(0);

	exit(1);

	/* Make the compiler happy */
	return 1;
}


int PCX_convert( char * psFileIn, char * psFileOut )
{

	int i,iRun,iImageSize,iBytesRead,iMaxRun,iBytesLeft, ic;
	FILE *fp, *fpo;
	unsigned char sHead[128], * pImage, *pIp, c;
	pcx_header *pInHead;
		

    /* Open the files */
	fp = fopen( psFileIn, "rb" );
	if ( !fp )
	{
		printf( "raq error : Cannot open %s for Binary Input\n", psFileIn );
		return 0;
	}

	if ( *psFileOut )
	{
		fpo = fopen( psFileOut, "wb" );
		if ( !fpo )
		{
			printf( "raq error : Cannot open %s for binary Output\n", psFileOut );
			return 0;
		}
	}
	else
		fpo = NULL;



	/* Read ther header */
	for( i = 0 ; i < 128 ; i++ )
		sHead[i] = (unsigned char)getc(fp);

	pInHead = ( pcx_header * )sHead;


	printf( "M:%d v:%d Enc:%d Bpp:%d Res:%d Cp:%d \n",
	(int)pInHead->manufacturer,
	(int)pInHead->version,
	(int)pInHead->encoding,
	(int)pInHead->bits_per_pixel,
	(int)pInHead->reserved,
	(int)pInHead->num_colour_planes );
	
	printf( "X:%d Y:%d W:%d H:%d Hr:%d Vr:%d Bpl:%d Pt:%d\n",
	(int)pInHead->x,
	(int)pInHead->y,
	(int)pInHead->width,
	(int)pInHead->height,
	(int)pInHead->horz_res,
	(int)pInHead->vert_res,
	(int)pInHead->bytes_per_line,
	(int)pInHead->palette_type );


	/* Covert the header for the output file if specified */
	if (fpo)
	{
		if ( pInHead->x > 0 )
		{
			pInHead->width -= pInHead->x;
			pInHead->x = ( short ) 0;
		}

		if ( pInHead->y > 0 )
		{
			pInHead->height -= pInHead->y;
			pInHead->y = ( short ) 0;
		}

		pInHead->horz_res = pInHead->width  + (short) 1;
		pInHead->vert_res = pInHead->height + (short) 1;
		

		printf( "Converted to :-\nX:%d Y:%d W:%d H:%d Hr:%d Vr:%d\n",
		(int)pInHead->x,
		(int)pInHead->y,
		(int)pInHead->width,
		(int)pInHead->height,
		(int)pInHead->horz_res,
		(int)pInHead->vert_res );

		for( i = 0 ; i < 128 ; i++ )
			putc( sHead[i], fpo );

	}


	iImageSize = ((int)pInHead->horz_res )* ( (int)pInHead->vert_res  );
	pImage = (unsigned char * ) malloc( (iImageSize +1 )* sizeof(unsigned char ));


	/* Read actual image data properly ( And why not ) */
	iBytesRead = 0;
	pIp = pImage;
	iMaxRun = 0;
	i = 0;
	while( i <= iImageSize )
	{
		ic = getc( fp );
		putc( ic, fpo );

		iBytesRead++;

		c = (unsigned char ) ic;
		if ( c >=192 )
		{
			iRun = ic - 192;
			ic = getc( fp );
			putc( ic, fpo );

			iBytesRead++;

			if ( iMaxRun < iRun ) iMaxRun = iRun;
			while( iRun-- )
			{
				*(pIp++) = (unsigned char)ic;
				i++;
			}	
		}
		else
		{
			*(pIp++) = (unsigned char )ic;
			i++;
		}
	}

	/* Read through the pallete */
	iBytesLeft = 0;
	while ( (ic = getc( fp )) != EOF )
	{
		putc( ic, fpo );
		iBytesLeft++;
	}

	printf( "Pcx File Stats\nByes in Image Data:%d Max Run:%d Image Size:%d Pallette size:%d\n", iBytesRead, iMaxRun, iImageSize, iBytesLeft );

	free( (void*) pImage);

	fclose(fp);
	if ( fpo ) fclose(fpo);

	return 1;
}



