; /*
sc RESOPT IGNORE=73 DATA=NEAR NMINC UCHAR CONSTLIB STREQ STRMERGE NOSTKCHK NOSTDIO OPTIMIZE OPTSIZE displayiff.c
slink from lib:c.o displayiff.o to //Clients/DisplayIFF lib /lib/client.lib lib:sc.lib lib:amiga20.lib SC SD NOICONS
delete displayiff.o
quit

 DisplayIFF 1.2  (Client for BServer)

 Copyright © 1994-1995 Stefano Reksten of 3AM - The Three Amigos!!!
 All rights reserved.

*/

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <datatypes/pictureclass.h>

#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/dos.h>
#include <proto/icon.h>
#include <clib/alib_protos.h>
#include <string.h>
#include <time.h>

#include "/include/client.h"
#include "/include/bitmap/bitmap.h"
#include "/include/bitmap/bitmap_pragmas.h"

#define BADFLAGS (SPRITES|VP_HIDE|GENLOCK_AUDIO|GENLOCK_VIDEO)
#define FLAGMASK (~BADFLAGS)
#define CAMGMASK (FLAGMASK & 0x0000FFFFL)

#define BMHDB_CMAPOK	7
#define BMHDF_CMAPOK	(1 << BMHDB_CMAPOK)

char *ver = "$VER: DisplayIFF 1.2 "__AMIGADATE__;

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *BitMapBase, *IconBase;

extern ULONG RangeSeed;

struct Screen *scr;
struct BitMap *iffbmap;
UBYTE *iffctable;
ULONG color_count, displayID;
char filename[128], drawername[128];
BOOL domask, iff_loaded;
struct BitMapHeader bmhd;
BPTR iffhandle;

UWORD top, left, delay = 1;
UBYTE frameptr = 0;
struct BitMap *bmap, *scalebmap, *preblitbmap;
struct RastPort preblitrport;

struct DisplayIDInformation *dinfo;
struct BitMapScaleInfo myscaleinfo = {
	NULL, NULL, NULL, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, NULL };


BOOL GetPicName( void )
{
struct DiskObject *dobj;
char **ttypes;
char *picname;
BOOL result = FALSE;

if ( IconBase = OpenLibrary( "icon.library", 0L ) )
	{
	if ( dobj = GetDiskObject( "DisplayIFF" ) )
		{
		ttypes = dobj->do_ToolTypes;
			if ( picname = FindToolType( ttypes, "PICTURE" ) )
				{
				strcpy( filename, picname );
				strcpy( drawername, picname );
				*(PathPart(drawername)) = 0;
				result = TRUE;
				}

		domask = (BOOL)FindToolType( ttypes, "MASK" );

		FreeDiskObject( dobj );
		}
	CloseLibrary( IconBase );
	}
return result;
}


void DisposeIFF( void )
{
if ( iffbmap )
	{
	DisposeBitMap( iffbmap );
	iffbmap = NULL;
	}
if ( iffctable )
	{
	FreeVec( iffctable );
	iffctable = NULL;
	}
}


BOOL ReadUncompressedFile( void )
{
UBYTE *address, plane;
UWORD row, bytesperrow;

bytesperrow = ((bmhd.bmh_Width+15)>>4)<<1;

for ( row = 0; row < bmhd.bmh_Height; row++ )
	{
	for ( plane = 0; plane < bmhd.bmh_Depth; plane++ )
		{
		address = iffbmap->Planes[plane] + row * iffbmap->BytesPerRow;
		if ( Read( iffhandle, address, bytesperrow ) != bytesperrow )
			return FALSE;
		}
	}
return TRUE;
}


BOOL ReadByteRun1( ULONG body_length )
{
BYTE *memory;
register BYTE *source;
register UBYTE plane, counter, *dest;
register UWORD row, bytesperrow, rowcounter;
BOOL result = FALSE;

if ( memory=(UBYTE *)AllocMem( body_length, MEMF_ANY|MEMF_CLEAR ) )
	{
	if ( body_length = Read( iffhandle, memory, body_length ) )
		{
		source = memory;

		bytesperrow = ((bmhd.bmh_Width+15)>>4)<<1;

		for ( row = 0; row < bmhd.bmh_Height; row++ )
			{
			for ( plane = 0; plane < bmhd.bmh_Depth; plane++ )
				{
				dest = iffbmap->Planes[plane] + row * iffbmap->BytesPerRow;
				for ( rowcounter = 0; rowcounter < bytesperrow; )
					{
					if ( *source == -128 )
						source++;
					else
					if ( *source >= 0 )
						{
						counter = *source++ + 1;
						rowcounter += counter;
						while( counter )
							{
							*dest++ = *source++;
							counter--;
							}
						}
					else
						{
						counter = 1 - *source++;
						rowcounter += counter;
						while( counter )
							{
							*dest++ = *source;
							counter--;
							}
						source++;
						}
					}
				}
			}
		FreeMem( memory, body_length );
		result = TRUE;
		}
	}
return result;
}
	

UBYTE ReadByte( void ) {
UBYTE my_byte;
Read( iffhandle, &my_byte, sizeof(UBYTE) );
return( my_byte ); }


ULONG ReadLong( void ) {
ULONG my_long;
Read( iffhandle, &my_long, sizeof(ULONG) );
return( my_long ); }


BOOL DecodeILBM( char *filename )
{
ULONG	total_read = 12, form_length, chunk_found, chunk_length;
UWORD	n;
BOOL	found_body = FALSE;

iff_loaded = FALSE;

if ( !( iffhandle = Open( filename, MODE_OLDFILE ) ) )
	goto end;

if ( ReadLong()!=ID_FORM )
	goto end;

form_length = ReadLong();

if ( ReadLong()!=ID_ILBM )
	goto end;

do
	{
	chunk_found = ReadLong();
	chunk_length = ReadLong();
	total_read += 4 + chunk_length;

	switch( chunk_found )
		{
		case	ID_BMHD:
			Read( iffhandle, &bmhd, sizeof(struct BitMapHeader) );
			if ( bmhd.bmh_Compression > 1 )
				goto end;
			if ( bmhd.bmh_Depth == 8 && domask )
				goto end;
			myscaleinfo.bsi_Width = bmhd.bmh_Width;
			myscaleinfo.bsi_Height = bmhd.bmh_Height;
			break;
		case	ID_CAMG:
			displayID = ReadLong() & CAMGMASK;
			if ( displayID & HAM )
				goto end;
			break;
		case	ID_CMAP:
			color_count = chunk_length/3;
			if ( displayID & EXTRA_HALFBRITE )
				color_count >>= 1;
			if ( iffctable = AllocVec( chunk_length, MEMF_ANY | MEMF_CLEAR ) )
			Read( iffhandle, iffctable, chunk_length );
			if ( !(bmhd.bmh_Pad & BMHDF_CMAPOK) )
				for ( n = 0; n < chunk_length; n++ )
					*(iffctable+n) = (*(iffctable+n) & 0xF0) + (*(iffctable+n)>>4);
			break;
		case	ID_BODY:
			found_body = TRUE;

			if ( !(iffbmap = CreateBitMap( bmhd.bmh_Width, bmhd.bmh_Height, bmhd.bmh_Depth + (domask?1:0) ) ) )
				goto end;
			
			if ( bmhd.bmh_Compression )
				iff_loaded = ReadByteRun1( chunk_length );
			else
				iff_loaded = ReadUncompressedFile();

			if ( iff_loaded && domask )
				{
				register UBYTE plane, *srcaddress, *dstaddress, bmhbpr;
				register UWORD byte, row;

				bmhbpr = ((bmhd.bmh_Width+15)>>4)<<1;
				for ( row = 0; row < bmhd.bmh_Height; row++ )
					for ( plane = 0; plane < bmhd.bmh_Depth; plane++ )
						{
						dstaddress = iffbmap->Planes[bmhd.bmh_Depth] + iffbmap->BytesPerRow * row;
						srcaddress = iffbmap->Planes[plane] + iffbmap->BytesPerRow * row;
						for ( byte = 0; byte < bmhbpr; byte++ )
							*dstaddress++ |= *srcaddress++;
						}
				}

			Close( iffhandle ); iffhandle = NULL;
			break;
		default:
			Seek( iffhandle, chunk_length, OFFSET_CURRENT );
			break;
		}
	}
	while( !found_body && total_read < form_length );

return TRUE;

end:
if ( iffhandle )
	{
	Close( iffhandle );
	iffhandle = NULL;
	}
DisposeIFF();
return FALSE;
}



void AnyIFF( void )
{
BOOL success = FALSE;
UWORD scaleN, scaleD, swidth, sheight, n, scaledw, scaledh;
struct Rectangle *rect;
UBYTE *address, brightness;

if ( DecodeILBM( filename ) && ( CheckAA() || bmhd.bmh_Depth <= (( displayID & EXTRA_HALFBRITE ) ? 6 : 5 )) )
	{
	rect = GETTXTOSCANRECT(dinfo);
	displayID = DISPLAYID(dinfo) | (displayID & EXTRA_HALFBRITE) | (displayID & LACE);

	swidth = RECTANGLEWIDTH(rect);

	if ( !CheckAA() )
		{
		if ( bmhd.bmh_Depth > 2 && (displayID & SUPERHIRES) )
			{
			displayID &= ~SUPERHIRES;
			swidth >>= 2;
			}
		else if ( bmhd.bmh_Depth > 4 && (displayID & HIRES) )
			{
			displayID &= ~HIRES;
			swidth >>= 1;
			}
		}

	if ( swidth <= bmhd.bmh_Width )
		swidth = (iffbmap->BytesPerRow<<3) + 1;

	sheight = RECTANGLEHEIGHT(rect);
	if ( sheight <= bmhd.bmh_Height )
		sheight = iffbmap->Rows + 1;

	brightness = GETBRIGHTNESS(dinfo);

	if ( bmap = CreateBitMap( bmhd.bmh_Width, bmhd.bmh_Height, bmhd.bmh_Depth + (domask?1:0) ) )
		{
		if ( scalebmap = CreateBitMap( bmhd.bmh_Width, bmhd.bmh_Height, bmhd.bmh_Depth + (domask?1:0) ) )
			{
			myscaleinfo.bsi_SrcBitMap = iffbmap;
			myscaleinfo.bsi_TempBitMap = scalebmap;
			myscaleinfo.bsi_DestBitMap = bmap;

			if ( preblitbmap = CreateBitMap( bmhd.bmh_Width, bmhd.bmh_Height, bmhd.bmh_Depth ) )
				{
				InitRastPort( &preblitrport );
				preblitrport.BitMap = preblitbmap;

				if ( scr = OpenScreenTags( NULL,
					SA_DisplayID, displayID,
					SA_Width, swidth,
					SA_Height, sheight,
					SA_Depth, bmhd.bmh_Depth,
					SA_Overscan, OSCAN_TEXT,
					SA_Type, CUSTOMSCREEN,
					SA_Quiet, TRUE,
					TAG_END ) )
					{
					register struct ViewPort *vp = &(scr->ViewPort);

					success = TRUE;

					SpritesOff();

					address = iffctable;
					for ( n = 0; n < color_count; n++ )
						SetRGB4( vp, n, (*address++>>4)*brightness/100, (*address++>>4)*brightness/100, (*address++>>4)*brightness/100 );

					frameptr = 0;

					while( STILL_BLANKING )
						{
						do {
							scaleN = RangeRand( 32 ) + 1;
							scaleD = RangeRand( 32 ) + 1;
							} while ( scaleN >= scaleD );

						myscaleinfo.bsi_HorNum = scaleN;
						myscaleinfo.bsi_VertNum = scaleN;
						myscaleinfo.bsi_HorDen = scaleD;
						myscaleinfo.bsi_VertDen = scaleD;

						scaledw = scaleN * bmhd.bmh_Width / scaleD;
						scaledh = scaleN * bmhd.bmh_Height / scaleD;

						left = RangeRand( swidth - scaledw - 1);
						top = RangeRand( sheight - scaledh - 1);

						myscaleinfo.bsi_Flags = NULL;
						if ( RangeRand( 2 ) == 0 )
							myscaleinfo.bsi_Flags |= BSIF_INVERTHOR;
						ScaleBitMap ( &myscaleinfo );

						if ( domask )
							{
							BltBitMap( scr->RastPort.BitMap, left, top, preblitbmap, 0, 0, scaledw, scaledh, 0xC0, 0xFF, NULL );
							BltMaskBitMapRastPort( bmap, 0, 0,
								&preblitrport, 0, 0,
								scaledw, scaledh, (ABC|ABNC|ANBC), (PLANEPTR)bmap->Planes[bmhd.bmh_Depth] );
							WaitTOF();
							BltBitMap( preblitbmap, 0, 0,  scr->RastPort.BitMap, left, top, scaledw, scaledh, 0xC0, 0xFF, NULL );
							}
						else
							BltBitMap( bmap, 0, 0,
								scr->RastPort.BitMap, left, top,
								scaledw, scaledh, 0xC0, 0xFF, NULL );

						}
					SpritesOn();
					CloseScreen( scr );
					}
				DisposeBitMap( preblitbmap );
				}
			DisposeBitMap( scalebmap );
			}
		DisposeBitMap( bmap );
		}
	DisposeIFF();
	}

if ( !success )
	SendClientMsg( ACTION_FAILED );
}


void __main( char *line )
{
if ( IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library", 36L ) )
	{
	if ( GfxBase = (struct GfxBase *)OpenLibrary( "graphics.library",0L ) )
		{
		if ( BitMapBase = OpenLibrary( "bitmap.library", 0L ) )
			{
			if ( dinfo = OpenCommunication() )
				{
				if ( GetPicName() )
					{
					RangeSeed = time( NULL );

					AnyIFF();
					CloseCommunication( dinfo );
					}
				else
					SendClientMsg( ACTION_FAILED );
				}
			CloseLibrary( BitMapBase );
			}
		CloseLibrary( (struct Library *)GfxBase );
		}
	CloseLibrary( (struct Library *)IntuitionBase );
	}
}
