/* $Revision Header * Header built automatically - do not edit! *************
 *
 *	(C) Copyright 1990 by MXM
 *
 *	Name .....: RemapIcon.c
 *	Created ..: Tuesday 26-Jun-90 14:19
 *	Revision .: 1
 *
 *	Date            Author          Comment
 *	=========       ========        ====================
 *	26-Jun-90       Olsen           Added Arp interface
 *	26-Jun-90       Olsen           Created this file!
 *
 * $Revision Header ********************************************************/

#define __NO_PRAGMAS 1

#include <workbench/workbench.h>
#include <libraries/arpbase.h>
#include <hardware/blit.h>
#include <exec/memory.h>
#include <functions.h>
#include <fcntl.h>

	/* Arp command line data. */

char *CLI_Template	= "File,DIR/K,TO/K,INFO/S";
char *CLI_Help		= "\nUsage: RemapIcon [FILE <Filename without .info>] [TO <Directory name>]\
\n                 [DIR <Directory name>] [TO <Directory name>]\
\n                 [INFO]\
\n\n                 Note: if the TO-argument is omitted, the icons will\
\n                       be written to the source directory.\n\n";

	/* Argument vector offsets. */

#define ARG_FILE	1
#define ARG_DIR		2
#define ARG_TO		3
#define ARG_INFO	4

	/* Icon.library base. */

struct Library *IconBase;

	/* Calculate the amount of memory needed for a row of pixels. */

#define byte(width) (((width + 15) >> 4) << 1)

	/* This is where the colour will go to. */

struct RastPort	ColourRPort;
struct BitMap	ColourBitMap;

	/* The icon image will be turned into a RastPort. */

struct RastPort	ImageRPort;
struct BitMap	ImageBitMap;

	/* Temporary mask and masks for both colours (1 and 2). */

struct BitMap	TempMask,ColourMask1,ColourMask2;

	/* RemapImage(struct Image *Icon):
	 *
	 *	This routine will exchange the colours of the white
	 *	and the black pixels in an image.
	 */

BYTE
RemapImage(struct Image *Icon)
{
	BYTE	Success = FALSE;
	SHORT	i;

		/* Transform the image into a RastPort. */

	InitRastPort(&ImageRPort);
	InitBitMap(&ImageBitMap,Icon -> Depth,Icon -> Width,Icon -> Height);
	ImageRPort . BitMap = &ImageBitMap;

		/* Set the planes accordingly. */

	for(i = 0 ; i < Icon -> Depth ; i++)
		ImageBitMap . Planes[i] = (PLANEPTR)((ULONG)Icon -> ImageData + i * byte(Icon -> Width) * Icon -> Height);

		/* Alas, you cannot perform an area fill through a mask wider
		 * than sixteen pixels. For this reason we will create a
		 * RastPort whose BitMap has the colour we want the
		 * mask area to be filled with.
		 */

	InitRastPort(&ColourRPort);
	InitBitMap(&ColourBitMap,Icon -> Depth,Icon -> Width,Icon -> Height);
	ColourRPort . BitMap = &ColourBitMap;

		/* Initialize the mask BitMaps. */

	InitBitMap(&TempMask,Icon -> Depth,Icon -> Width,Icon -> Height);
	InitBitMap(&ColourMask1,Icon -> Depth,Icon -> Width,Icon -> Height);
	InitBitMap(&ColourMask2,Icon -> Depth,Icon -> Width,Icon -> Height);

		/* Allocate memory for the colour BitMap. */

	if(ColourBitMap . Planes[0] = (PLANEPTR)AllocMem(Icon -> Depth * byte(Icon -> Width) * Icon -> Height,MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR))
	{
		for(i = 1 ; i < Icon -> Depth ; i++)
			ColourBitMap . Planes[i] = (PLANEPTR)((ULONG)ColourBitMap . Planes[0] + i * byte(Icon -> Width) * Icon -> Height);

			/* Allocate memory for the mask for colour 1. */

		if(ColourMask1 . Planes[0] = (PLANEPTR)AllocMem(byte(Icon -> Width) * Icon -> Height,MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR))
		{
			for(i = 1 ; i < Icon -> Depth ; i++)
				ColourMask1 . Planes[i] = ColourMask1 . Planes[0];

				/* Allocate memory for the mask for colour 2. */

			if(ColourMask2 . Planes[0] = (PLANEPTR)AllocMem(byte(Icon -> Width) * Icon -> Height,MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR))
			{
				for(i = 1 ; i < Icon -> Depth ; i++)
					ColourMask2 . Planes[i] = ColourMask2 . Planes[0];

					/* Allocate memory for the temporary mask. */

				if(TempMask . Planes[0] = (PLANEPTR)AllocMem(byte(Icon -> Width) * Icon -> Height,MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR))
				{
					Success = TRUE;

					for(i = 1 ; i < Icon -> Depth ; i++)
						TempMask . Planes[i] = TempMask . Planes[0];

						/* Perform an OR-operation on all the planes associated with colour 1. */

					BltBitMap(&ImageBitMap,0,0,&ColourMask1,0,0,Icon -> Width,Icon -> Height,0xE0,1,NULL);

						/* Clear all pixels in the mask which belong to other colours. */

					BltBitMap(&ImageBitMap,0,0,&ColourMask1,0,0,Icon -> Width,Icon -> Height,0x80,1,NULL);

						/* Perform an OR-operation on all planes which do not belong to colour 1. */

					BltBitMap(&ImageBitMap,0,0,&TempMask,0,0,Icon -> Width,Icon -> Height,0xE0,0xFF ^ 1,NULL);

						/* Clear all pixels which do not belong to colour 1. */

					BltBitMap(&TempMask,0,0,&ColourMask1,0,0,Icon -> Width,Icon -> Height,0x20,0xFF,NULL);

						/* Clear the temporary mask. */

					BltClear(TempMask . Planes[0],byte(Icon -> Width) * Icon -> Height,1);

						/* Perform an OR-operation on all the planes associated with colour 2. */

					BltBitMap(&ImageBitMap,0,0,&ColourMask2,0,0,Icon -> Width,Icon -> Height,0xE0,2,NULL);

						/* Clear all pixels in the mask which belong to other colours. */

					BltBitMap(&ImageBitMap,0,0,&ColourMask2,0,0,Icon -> Width,Icon -> Height,0x80,2,NULL);

						/* Perform an OR-operation on all planes which do not belong to colour 2. */

					BltBitMap(&ImageBitMap,0,0,&TempMask,0,0,Icon -> Width,Icon -> Height,0xE0,0xFF ^ 2,NULL);

						/* Clear all pixels which do not belong to colour 1. */

					BltBitMap(&TempMask,0,0,&ColourMask2,0,0,Icon -> Width,Icon -> Height,0x20,0xFF,NULL);

						/* Replace colour 2 with colour 1. */

					SetRast(&ColourRPort,1);

					BltMaskBitMapRastPort(&ColourBitMap,0,0,&ImageRPort,0,0,Icon -> Width,Icon -> Height,(ABC|ABNC|ANBC),(APTR)ColourMask2 . Planes[0]);

						/* Replace colour 1 with colour 2. */

					SetRast(&ColourRPort,2);

					BltMaskBitMapRastPort(&ColourBitMap,0,0,&ImageRPort,0,0,Icon -> Width,Icon -> Height,(ABC|ABNC|ANBC),(APTR)ColourMask1 . Planes[0]);

					FreeMem(TempMask . Planes[0],byte(Icon -> Width) * Icon -> Height);
				}

				FreeMem(ColourMask2 . Planes[0],byte(Icon -> Width) * Icon -> Height);
			}

			FreeMem(ColourMask1 . Planes[0],byte(Icon -> Width) * Icon -> Height);
		}

		FreeMem(ColourBitMap . Planes[0],Icon -> Depth * byte(Icon -> Width) * Icon -> Height);
	}

	return(Success);
}

	/* RemapIcon(char *Source,char *Dest):
	 *
	 *	This routine loads the approriate icon file, causes
	 *	the image(s) to be remapped and saves the resulting
	 *	file back to disk.
	 */

BYTE
RemapIcon(char *Source,char *Dest)
{
	struct DiskObject	*Icon;
	BYTE			 Success = FALSE;

	Printf("Remapping icon %s.info to %s.info... ",Source,Dest);

		/* Read the icon file. */

	if(Icon = GetDiskObject(Source))
	{
			/* Remap the standard image. */

		if(RemapImage((struct Image *)Icon -> do_Gadget . GadgetRender))
		{
			Success = TRUE;

				/* If it has an alternate image, remap it as well. */

			if(Icon -> do_Gadget . SelectRender)
			{
				if(!RemapImage((struct Image *)Icon -> do_Gadget . SelectRender))
				{
					Printf("ERROR (%ld): Cannot remap icon select image.\a\n",ERROR_NO_FREE_STORE);
					Success = FALSE;
				}
			}

				/* If the remapping process succeeded, save
				 * the icon back to disk.
				 */

			if(Success)
			{
				if(!PutDiskObject(Dest,Icon))
				{
					Printf("ERROR (%ld): Cannot create file \"%s.info\".\a\n",IoErr(),Dest);
					Success = FALSE;
				}
			}
		}
		else
			Printf("ERROR (%ld): Cannot remap icon image.\a\n",ERROR_NO_FREE_STORE);

			/* Release the icon. */

		FreeDiskObject(Icon);
	}
	else
		Printf("ERROR (%ld): Cannot read file \"%s.info\".\a\n",IoErr(),Source);

	if(Success)
		Puts("done.");

	return(Success);
}

LONG Chk_Abort(VOID) { return(0); }
VOID _wb_parse(VOID) {}

VOID
main(int argc,char **argv)
{
	BYTE Success = RETURN_OK;

		/* Disable the standard ^C checking. */

	Enable_Abort = FALSE;

		/* Display program version. */

	Puts("\n\33[1m\33[33mRemapIcon V1.1 \33[0m\33[31mCopyright © 1990 by MXM, all rights reserved\n");

		/* User wants info? */

	if(argv[ARG_INFO])
	{
		Puts("This  program remaps icon images to fit the different colour");
		Puts("palettes used by Amiga computers equipped with Kickstart 2.x");
		Puts("and  1.3.   The  colours of pixels painted in colour 1 and 2");
		Puts("are  swapped,   so  pre-2.x  icons   and  2.x  icons  can be");
		Puts("exchanged between both Workbench releases.\n");

		Puts("Author: Olaf Barthel, MXM");
		Puts("        Brabeckstrasse 35");
		Puts("        D-3000 Hannover 71\n");

		Puts("        Federal Republic of Germany\n");

		Puts("Written at Hannover, Monday 25-Jun-90.\n");

		Puts("This  program  is  Share-Ware,  if  you  like  it and use it");
		Puts("frequently  a  small  donation  will  entitle you to receive");
		Puts("updates and new programs from MXM.\n");

		exit(RETURN_OK);
	}

		/* Do we have a valid command line? */

	if(!argv[ARG_FILE] && !argv[ARG_DIR])
	{
		Puts(CLI_Help);
		exit(RETURN_WARN);
	}

		/* Open icon.library. */

	if(IconBase = OpenLibrary("icon.library",0))
	{
		char DestName[256];

			/* Convert a single file? */

		if(argv[ARG_FILE])
		{
				/* Do we have a path to write it to? */

			if(argv[ARG_TO])
			{
				strcpy(DestName,argv[ARG_TO]);
				TackOn(DestName,BaseName(argv[ARG_FILE]));
			}
			else
			{
				SHORT i;

				strcpy(DestName,argv[ARG_FILE]);

				for(i = strlen(DestName) - 1 ; i >= 0 ; i--)
				{
					if(DestName[i] == ':' || DestName[i] == '/')
						break;
					else
						DestName[i] = 0;
				}

				strcat(DestName,BaseName(argv[ARG_FILE]));
			}

				/* Remap the icon. */

			if(!RemapIcon(argv[ARG_FILE],DestName))
				Success = RETURN_FAIL;
		}
		else
		{
			char SourceName[256],Pattern[256],*Pointer;

				/* Build search path and pattern. */

			strcpy(Pattern,argv[ARG_DIR]);
			TackOn(Pattern,"*.info");

				/* Scan the directory for .info files. */

			while(Pointer = scdir(Pattern))
			{
					/* ^C = Abort scanning. */

				if(SetSignal(0,0) & SIGBREAKF_CTRL_C)
				{
					SetSignal(0,SIGBREAKF_CTRL_C);

					Puts("*** Break\a");
					break;
				}

					/* ^D skip current file. */

				if(SetSignal(0,0) & SIGBREAKF_CTRL_D)
				{
					SetSignal(0,SIGBREAKF_CTRL_D);
					continue;
				}

					/* Is it an icon file? */

				if(strlen(BaseName(Pointer)) > 5)
				{
					strcpy(SourceName,Pointer);

						/* Skip the .info. */

					SourceName[strlen(SourceName) - 5] = 0;

						/* Do we have a path to write it to? */

					if(argv[ARG_TO])
					{
						strcpy(DestName,argv[ARG_TO]);
						TackOn(DestName,BaseName(SourceName));
					}
					else
					{
						SHORT i;

						strcpy(DestName,SourceName);

						for(i = strlen(DestName) - 1 ; i >= 0 ; i--)
						{
							if(DestName[i] == ':' || DestName[i] == '/')
								break;
							else
								DestName[i] = 0;
						}

						strcat(DestName,BaseName(SourceName));
					}

						/* Remap the icon. */

					RemapIcon(SourceName,DestName);
				}
			}
		}

			/* Close the library. */

		CloseLibrary(IconBase);
	}
	else
	{
		Printf("ERROR (%ld): Cannot open icon.library.\a\n",IoErr());
		Success = RETURN_FAIL;
	}

		/* And return. */

	exit(Success);
}
