/*
**	termScale.c
**
**	Single scaled character output routines
**
**	Copyright © 1990-1992 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* Some static data required by the bitmap scaling routine. */

STATIC struct RastPort		*ScaleRPort;
STATIC struct BitMap		*ScaleSrcBitMap,
				*ScaleDstBitMap;
STATIC struct BitScaleArgs	*ScaleArgs;

STATIC WORD			 ScaleCache = -1,
				 PlaneWidth,
				 PlaneHeight;

	/* DeleteScale():
	 *
	 *	Frees all the data associated with font scaling.
	 */

VOID
DeleteScale()
{
	WORD i;

	if(ScaleArgs)
	{
		FreeVec(ScaleArgs);

		ScaleArgs = NULL;
	}

	if(ScaleDstBitMap)
	{
		for(i = 0 ; i < ScaleDstBitMap -> Depth ; i++)
		{
			if(ScaleDstBitMap -> Planes[i])
				FreeRaster(ScaleDstBitMap -> Planes[i],PlaneWidth * 2,PlaneHeight * 2);
		}

		FreeVec(ScaleDstBitMap);

		ScaleDstBitMap = NULL;
	}

	if(ScaleSrcBitMap)
	{
		for(i = 0 ; i < ScaleSrcBitMap -> Depth ; i++)
		{
			if(ScaleSrcBitMap -> Planes[i])
				FreeRaster(ScaleSrcBitMap -> Planes[i],PlaneWidth,PlaneHeight);
		}

		FreeVec(ScaleSrcBitMap);

		ScaleSrcBitMap = NULL;
	}

	if(ScaleRPort)
	{
		FreeVec(ScaleRPort);

		ScaleRPort = NULL;
	}
}

	/* CreateScale():
	 *
	 *	Sets up the data required for real-time font scaling
	 *	(bitmaps, rastports, etc.).
	 */

BYTE
CreateScale()
{
		/* Create a RastPort to render into. */

	if(ScaleRPort = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY|MEMF_CLEAR))
	{
		WORD MaxWidth,i;

		if(GFX)
			MaxWidth = GFX -> tf_XSize;
		else
			MaxWidth = 0;

		if(TextFontWidth > MaxWidth)
			MaxWidth = TextFontWidth;

			/* Remember dimensions. */

		PlaneWidth	= MaxWidth;
		PlaneHeight	= TextFontHeight;

			/* Initialize it. */

		InitRastPort(ScaleRPort);

			/* Create the bitmap to render into. */

		if(ScaleSrcBitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap),MEMF_ANY|MEMF_CLEAR))
		{
				/* Create the bitmap to place the scaled font data into. */

			if(ScaleDstBitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap),MEMF_ANY|MEMF_CLEAR))
			{
				BYTE AllFine = TRUE;

					/* Initialize the bitmap. */

				InitBitMap(ScaleSrcBitMap,Screen -> RastPort . BitMap -> Depth,PlaneWidth,PlaneHeight);

					/* Allocate the necessary memory space. */

				for(i = 0 ; i < ScaleSrcBitMap -> Depth ; i++)
				{
					if(!(ScaleSrcBitMap -> Planes[i] = AllocRaster(PlaneWidth,PlaneHeight)))
					{
						AllFine = FALSE;

						break;
					}
				}

				if(AllFine)
				{
						/* Initialize destination bitmap, it must be
						 * able to hold four times the size of the
						 * source data.
						 */

					InitBitMap(ScaleDstBitMap,Screen -> RastPort . BitMap -> Depth,PlaneWidth * 2,PlaneHeight * 2);

						/* Allocate space for the destination area. */

					for(i = 0 ; i < ScaleDstBitMap -> Depth ; i++)
					{
						if(!(ScaleDstBitMap -> Planes[i] = AllocRaster(PlaneWidth * 2,PlaneHeight * 2)))
						{
							AllFine = FALSE;

							break;
						}
					}

					if(AllFine)
					{
							/* Put the source bitmap into the source RastPort. */

						ScaleRPort -> BitMap = ScaleSrcBitMap;

							/* Install the fonts. */

						SetFont(ScaleRPort,CurrentFont);

							/* Set the default rendering pens. */

						SetAPen(ScaleRPort,1);
						SetBPen(ScaleRPort,0);

							/* By default, overwrite data. */

						SetDrMd(ScaleRPort,JAM2);

							/* Allocate space for the bitmap scaling arguments. */

						if(ScaleArgs = (struct BitScaleArgs *)AllocVec(sizeof(struct BitScaleArgs),MEMF_ANY|MEMF_CLEAR))
						{
								/* Initialize the structure. */

							ScaleArgs -> bsa_SrcWidth	= TextFontWidth;
							ScaleArgs -> bsa_SrcHeight	= TextFontHeight;

							ScaleArgs -> bsa_YSrcFactor	= 1;

							ScaleArgs -> bsa_SrcBitMap	= ScaleSrcBitMap;
							ScaleArgs -> bsa_DestBitMap	= ScaleDstBitMap;

							return(TRUE);
						}
					}
				}
			}
		}
	}

	return(FALSE);
}

	/* PrintScaled(UBYTE Char,UBYTE Scale):
	 *
	 *	This is the big one: since VT100 supports a number of
	 *	font sizes (double height, double width, 132 columns),
	 *	the approriate characters are scaled in real-time before
	 *	they are displayed.
	 */

VOID __regargs
PrintScaled(UBYTE *Buffer,LONG Size,UBYTE Scale)
{
	UWORD SrcY,DestX,DestY,SizeX,Baseline;

		/* Determine the scale of the destination character. */

	if(Config . EmulationConfig . FontScale == SCALE_HALF)
	{
			/* Determine scale to be used. */

		switch(Scale)
		{
				/* Half width. */

			case SCALE_ATTR_NORMAL:

				ScaleArgs -> bsa_XDestFactor	= 1;
				ScaleArgs -> bsa_YDestFactor	= 1;
				ScaleArgs -> bsa_XSrcFactor	= 2;

				SrcY	= 0;
				DestX	= CursorX * TextFontWidth / 2;
				SizeX	= TextFontWidth / 2;

				ScaleCache = -1;

				break;

				/* Half width, double height (top bits). */

			case SCALE_ATTR_TOP2X:

				ScaleArgs -> bsa_XDestFactor	= 1;
				ScaleArgs -> bsa_YDestFactor	= 2;
				ScaleArgs -> bsa_XSrcFactor	= 1;

				SrcY	= 0;
				DestX	= CursorX * TextFontWidth;
				SizeX	= TextFontWidth;

				ScaleCache = -1;

				break;

				/* Half width, double height (bottom bits). */

			case SCALE_ATTR_BOT2X:

				ScaleArgs -> bsa_XDestFactor	= 1;
				ScaleArgs -> bsa_YDestFactor	= 2;
				ScaleArgs -> bsa_XSrcFactor	= 1;

				SrcY	= TextFontHeight;
				DestX	= CursorX * TextFontWidth;
				SizeX	= TextFontWidth;

				ScaleCache = -1;

				break;
		}
	}
	else
	{
			/* Determine scale to be used. */

		switch(Scale)
		{
				/* Double height (top bits). */

			case SCALE_ATTR_TOP2X:

				ScaleArgs -> bsa_XDestFactor	= 2;
				ScaleArgs -> bsa_YDestFactor	= 2;
				ScaleArgs -> bsa_XSrcFactor	= 1;

				SrcY	= 0;
				DestX	= CursorX * TextFontWidth * 2;
				SizeX	= TextFontWidth * 2;

				ScaleCache = -1;

				break;

				/* Double height (bottom bits). */

			case SCALE_ATTR_BOT2X:

				ScaleArgs -> bsa_XDestFactor	= 2;
				ScaleArgs -> bsa_YDestFactor	= 2;
				ScaleArgs -> bsa_XSrcFactor	= 1;

				SrcY	= TextFontHeight;
				DestX	= CursorX * TextFontWidth * 2;
				SizeX	= TextFontWidth * 2;

				ScaleCache = -1;

				break;

				/* Double width. */

			case SCALE_ATTR_2X:

				ScaleArgs -> bsa_XDestFactor	= 2;
				ScaleArgs -> bsa_YDestFactor	= 1;
				ScaleArgs -> bsa_XSrcFactor	= 1;

				SrcY	= 0;
				DestX	= CursorX * TextFontWidth * 2;
				SizeX	= TextFontWidth * 2;

				ScaleCache = -1;

				break;
		}
	}

		/* Look for the font type to scale. */

	if(ScaleRPort -> Font != CurrentFont)
	{
		SetFont(ScaleRPort,CurrentFont);

		ScaleArgs -> bsa_SrcWidth = TextFontWidth;

		ScaleCache = -1;
	}

		/* Set the approriate colours. */

	if(ScaleRPort -> FgPen != RPort -> FgPen)
	{
		SetAPen(ScaleRPort,RPort -> FgPen);

		ScaleCache = -1;
	}

	if(ScaleRPort -> BgPen != RPort -> BgPen)
	{
		SetBPen(ScaleRPort,RPort -> BgPen);

		ScaleCache = -1;
	}

		/* Calculate topmost line to write to. */

	DestY = CursorY * TextFontHeight;

		/* Remember the font baseline. */

	Baseline = CurrentFont -> tf_Baseline;

	if(CurrentFont == GFX)
	{
		BYTE Mode = 1;

			/* Run down the buffer... */

		while(Size--)
		{
			if(GfxTable[*Buffer] == Mode)
			{
				if(*Buffer != ScaleCache)
				{
					ScaleCache = *Buffer;

						/* Print the character to be scaled into the
						 * invisible drawing area.
						 */

					Move(ScaleRPort,0,Baseline);

					Text(ScaleRPort,Buffer++,1);

						/* Scale the font. */

					BitMapScale(ScaleArgs);
				}
				else
					Buffer++;

					/* Render the character. */

				BltBitMapRastPort(ScaleDstBitMap,0,SrcY,RPort,DestX,DestY,SizeX,TextFontHeight,0xC0);
			}
			else
			{
				ScaleCache = *Buffer;

				if(Mode)
					SetFont(ScaleRPort,TextFont);
				else
					SetFont(ScaleRPort,GFX);

				Mode ^= 1;

					/* Print the character to be scaled into the
					 * invisible drawing area.
					 */

				Move(ScaleRPort,0,Baseline);

				Text(ScaleRPort,Buffer++,1);

					/* Scale the font. */

				BitMapScale(ScaleArgs);

					/* Render the character. */

				BltBitMapRastPort(ScaleDstBitMap,0,SrcY,RPort,DestX,DestY,SizeX,TextFontHeight,0xC0);
			}

			DestX += SizeX;
		}

		if(!Mode)
			SetFont(ScaleRPort,GFX);
	}
	else
	{
			/* Run down the buffer... */

		while(Size--)
		{
			if(*Buffer != ScaleCache)
			{
				ScaleCache = *Buffer;

					/* Print the character to be scaled into the
					 * invisible drawing area.
					 */

				Move(ScaleRPort,0,Baseline);

				Text(ScaleRPort,Buffer++,1);

					/* Scale the font. */

				BitMapScale(ScaleArgs);
			}
			else
				Buffer++;

				/* Render the character. */

			BltBitMapRastPort(ScaleDstBitMap,0,SrcY,RPort,DestX,DestY,SizeX,TextFontHeight,0xC0);

			DestX += SizeX;
		}
	}
}
