/** Revision Header * Header built automatically - do not edit! *************
 *
 *	(C) Copyright 1991 by Olaf `Olsen' Barthel, all rights reserved
 *
 *	Name .....: SaveILBM.c
 *	Created ..: Monday 26-Aug-91 11:20
 *	Revision .: 1
 *
 *	Date            Author          Comment
 *	=========       ========        ====================
 *	26-Aug-91	Olsen		Created this file!
 *
 ***************************************************************************/

	/* This is basically Jim Kent's IFF-ILBM writer code as published
	 * in `Plop', with changes for iffparse.library and 32 bit viewmode
	 * CAMG chunks. I also added a version chunk to be saved with each
	 * image.
	 */

#define DUMP	0
#define RUN	1

#define MINRUN	3
#define MAXRUN	128
#define MAXDAT	128

#define IFF_SIZE	4096

STATIC UBYTE	IFFBuffer[IFF_SIZE];
STATIC WORD	IFFSize;

STATIC BYTE __regargs
FlushIFF(struct IFFHandle *IFFHandle)
{
	if(IFFSize)
	{
		if(WriteChunkBytes(IFFHandle,IFFBuffer,IFFSize) != IFFSize)
		{
			IFFSize = 0;
			return(FALSE);
		}

		IFFSize = 0;
	}

	return(TRUE);
}

STATIC BYTE __regargs
PutIFF(struct IFFHandle *IFFHandle,UBYTE c)
{
	if(IFFSize == IFF_SIZE)
		if(!FlushIFF(IFFHandle))
			return(FALSE);

	IFFBuffer[IFFSize++] = c;

	return(TRUE);
}

STATIC BYTE __regargs
WriteIFF(struct IFFHandle *IFFHandle,UBYTE *Data,LONG Size)
{
	LONG Len;

	while(Size)
	{
		if(IFFSize == IFF_SIZE)
			if(!FlushIFF(IFFHandle))
				return(FALSE);

		if((Len = Size) > IFF_SIZE - IFFSize)
			Len = IFF_SIZE - IFFSize;

		CopyMem(&Data[0],&IFFBuffer[IFFSize],Len);

		IFFSize	+= Len;
		Size	-= Len;

		Data = &Data[Len];
	}

	return(TRUE);
}

STATIC LONG __regargs
PackRow(struct IFFHandle *FileHandle,UBYTE *Source,LONG Size)
{
	UBYTE	c,LastByte = 0,LineBuf[MAXDAT * 3 / 2];
	BYTE	CompMode = DUMP;
	WORD	InBuf = 1,RunStart = 0;
	LONG 	PutSize = 0;

	LineBuf[0] = LastByte = *Source++;

	Size--;

	for( ; Size ; --Size)
	{
		LineBuf[InBuf++] = c = *Source++;

		switch(CompMode)
		{
			case DUMP:	if(InBuf > MAXDAT)
					{
						if(!PutIFF(FileHandle,InBuf-2))
							return(FALSE);

						if(!WriteIFF(FileHandle,LineBuf,InBuf-1))
							return(0);

						PutSize += InBuf;
						LineBuf[0] = c;
						InBuf = 1;
						RunStart = 0;
						break;
					}

					if(c == LastByte)
					{
						if(InBuf - RunStart >= MINRUN)
						{
							if(RunStart > 0)
							{
								if(!PutIFF(FileHandle,RunStart-1))
									return(FALSE);

								if(!WriteIFF(FileHandle,LineBuf,RunStart))
									return(0);

								PutSize += RunStart+1;
							}

							CompMode = RUN;
						}
						else
						{
							if(!RunStart)
								CompMode = RUN;
						}
					}
					else
						RunStart = InBuf - 1;

					break;

			case RUN:	if((c != LastByte) || (InBuf - RunStart > MAXRUN))
					{
						if(!PutIFF(FileHandle,-(InBuf - RunStart - 2)))
							return(FALSE);

						if(!PutIFF(FileHandle,LastByte))
							return(FALSE);

						PutSize += 2;

						LineBuf[0] = c;
						InBuf = 1;
						RunStart = 0;
						CompMode = DUMP;
					}

					break;
		}

		LastByte = c;
	}

	switch(CompMode)
	{
		case DUMP:	if(!PutIFF(FileHandle,InBuf-1))
					return(FALSE);

				if(!WriteIFF(FileHandle,LineBuf,InBuf))
					return(FALSE);

				PutSize += InBuf+1;
				break;

		case RUN:	if(!PutIFF(FileHandle,-(InBuf - RunStart - 1)))
					return(FALSE);

				if(!PutIFF(FileHandle,LastByte))
					return(FALSE);

				PutSize += 2;
				break;
	}

	return(PutSize);
}

STATIC LONG __regargs
PackBitMap(struct IFFHandle *FileHandle,struct BitMap *BitMap,LONG Height)
{
	LONG i,j,RowLength,CompressedLength = 0,PlaneOffset = 0;

	for(i = 0 ; i < Height ; i++)
	{
		for(j = 0 ; j < BitMap -> Depth ; j++)
		{
			if(!(RowLength = PackRow(FileHandle,BitMap -> Planes[j] + PlaneOffset,BitMap -> BytesPerRow)))
				return(0);

			CompressedLength += RowLength;
		}

		PlaneOffset += BitMap -> BytesPerRow;
	}

	return(CompressedLength);
}

STATIC BYTE __regargs
WriteILBM(UBYTE *FileName,UBYTE *Colours,struct BitMap *BitMap,LONG OffsetX,BYTE OffsetY,LONG Width,LONG Height,LONG Compressed,LONG PageWidth,LONG PageHeight,ULONG ViewModes,struct MandelInfo *MandelInfo)
{
	struct IFFHandle	*FileHandle;
	struct BitMapHeader	 BitMapHeader;
	LONG			 RowOffset;
	LONG			 i,j;
	WORD			 NumColours = 32;
	BYTE			 Success = TRUE;

	if(BitMap)
	{
		if((NumColours = 1 << BitMap -> Depth) > 32)
			NumColours = 32;

		if(ViewModes & HAM)
			NumColours = 16;
	}

	if(FileHandle = AllocIFF())
	{
		if(FileHandle -> iff_Stream = Open(FileName,MODE_NEWFILE))
		{
			InitIFFasDOS(FileHandle);

			if(!OpenIFF(FileHandle,IFFF_WRITE))
			{
				if(!PushChunk(FileHandle,'ILBM','FORM',IFFSIZE_UNKNOWN))
				{
					BitMapHeader . masking		= 0;
					BitMapHeader . pad1		= 0;
					BitMapHeader . transparentColor	= 0;

					if(Compressed)
						BitMapHeader . compression = 1;
					else
						BitMapHeader . compression = 0;

					BitMapHeader . pageWidth	= PageWidth;
					BitMapHeader . pageHeight	= PageHeight;
					BitMapHeader . yAspect		= 11;

					ViewModes &= ~(SPRITES | VP_HIDE | GENLOCK_AUDIO | GENLOCK_VIDEO);

					if((ViewModes & HIRES) && (ViewModes & LACE))
						BitMapHeader . xAspect = 10;

					if(!(ViewModes & HIRES) && (ViewModes & LACE))
						BitMapHeader . xAspect = 20;

					if((ViewModes & HIRES) && !(ViewModes & LACE))
						BitMapHeader . xAspect = 5;

					if(!(ViewModes & HIRES) && !(ViewModes & LACE))
						BitMapHeader . xAspect = 10;

					if(BitMap)
					{
						BitMapHeader . w	= Width;
						BitMapHeader . h	= Height;
						BitMapHeader . nPlanes	= BitMap -> Depth;
						BitMapHeader . x	= OffsetX;
						BitMapHeader . y	= OffsetY;
					}

					if(!PushChunk(FileHandle,0,'BMHD',IFFSIZE_UNKNOWN))
					{
						if(WriteChunkBytes(FileHandle,&BitMapHeader,sizeof(BitMapHeader)) == sizeof(BitMapHeader))
						{
							if(!PopChunk(FileHandle))
							{
								if(!PushChunk(FileHandle,0,'CMAP',IFFSIZE_UNKNOWN))
								{
									if(WriteChunkBytes(FileHandle,Colours,3 * NumColours) == 3 * NumColours)
									{
										if(!PopChunk(FileHandle))
										{
											if(!PushChunk(FileHandle,0,'CAMG',IFFSIZE_UNKNOWN))
											{
												if(WriteChunkBytes(FileHandle,&ViewModes,sizeof(ULONG)) == sizeof(ULONG))
												{
													if(!PopChunk(FileHandle))
													{
														if(!PushChunk(FileHandle,0,'MAND',IFFSIZE_UNKNOWN))
														{
															if(WriteChunkBytes(FileHandle,MandelInfo,sizeof(struct MandelInfo)) == sizeof(struct MandelInfo))
															{
																if(!PopChunk(FileHandle))
																{
																	if(!PushChunk(FileHandle,0,'ANNO',IFFSIZE_UNKNOWN))
																	{
																		extern UBYTE	VersTag[];
																		UBYTE		Len;

																		Len = strlen(&VersTag[1]);

																		if(WriteChunkBytes(FileHandle,&VersTag[1],Len) != Len)
																			Success = FALSE;
																		else
																		{
																			if(PopChunk(FileHandle))
																				Success = FALSE;
																		}
																	}

																	if(Success)
																	{
																		if(!PushChunk(FileHandle,0,'BODY',IFFSIZE_UNKNOWN))
																		{
																			if(Compressed)
																			{
																				if(!PackBitMap(FileHandle,BitMap,Height))
																					Success = FALSE;
																				else
																				{
																					if(!FlushIFF(FileHandle))
																						Success = FALSE;
																				}
																			}
																			else
																			{
																				i = Height;
																				RowOffset = 0;

																				while(--i >= 0 && Success)
																				{
																					for(j = 0 ; j < BitMap -> Depth ; j++)
																					{
																						if(WriteChunkBytes(FileHandle,BitMap -> Planes[j] + RowOffset,Height) != Height)
																						{
																							Success = FALSE;
																							break;
																						}

																						RowOffset += BitMap -> BytesPerRow;
																					}
																				}
																			}
	
																			if(PopChunk(FileHandle))
																				Success = FALSE;
																		}
																	}
																	else
																		Success = FALSE;
																}
																else
																	Success = FALSE;
															}
															else
																Success = FALSE;
														}
														else
															Success = FALSE;
													}
													else
														Success = FALSE;
												}
												else
													Success = FALSE;
											}
											else
												Success = FALSE;
										}
										else
											Success = FALSE;
									}
									else
										Success = FALSE;
								}
								else
									Success = FALSE;
							}
							else
								Success = FALSE;
						}
						else
							Success = FALSE;
					}
					else
						Success = FALSE;

					if(PopChunk(FileHandle))
						Success = FALSE;
				}
				else
					Success = FALSE;
			}
			else
				Success = FALSE;

			Close(FileHandle -> iff_Stream);
		}
		else
			Success = FALSE;

		FreeIFF(FileHandle);
	}
	else
		Success = FALSE;

	return(Success);
}

LONG
SaveBitMap(struct BitMap *BitMap,struct ViewPort *VPort,LONG LeftEdge,LONG TopEdge,LONG Width,LONG Height,LONG ParentWidth,LONG ParentHeight,STRPTR Name,struct MandelInfo *MandelInfo)
{
	extern struct GfxBase	*GfxBase;

	UBYTE			 ColTable[32 * 3];
	LONG			 IFF_Result,i,r,g,b;

	IFFSize = 0;

	for(i = 0 ; i < 32 ; i++)
	{
		UWORD TmpCol = GetRGB4(VPort -> ColorMap,i);

		r = (TmpCol >> 8) & 0xF;
		g = (TmpCol >> 4) & 0xF;
		b = (TmpCol     ) & 0xF;

		ColTable[i * 3 + 0] = r << 4;
		ColTable[i * 3 + 1] = g << 4;
		ColTable[i * 3 + 2] = b << 4;
	}

	if(!(IFF_Result = WriteILBM(Name,ColTable,BitMap,LeftEdge,TopEdge,Width,Height,TRUE,ParentWidth,ParentHeight,GetVPModeID(VPort),MandelInfo)))
		DeleteFile(Name);
	else
		SetProtection(Name,FIBF_EXECUTE);

	return(IFF_Result);
}
