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

 PT_Player 1.0  (Client for BServer)

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

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/interrupts.h>
#include <intuition/intuition.h>
#include <datatypes/pictureclass.h>
#include <libraries/iffparse.h>
#include <utility/tagitem.h>
#include <dos/dos.h>

#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/dos.h>
#include <string.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: PT_Player 1.1 "__AMIGADATE__;

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct GfxBase *GfxBase;
struct Library *BitMapBase;
struct DisplayIDInformation *dinfo;

int frames, vframes;

struct BitMap *iffbmap;
UBYTE *iffctable;
ULONG color_count, displayID;
BOOL iff_loaded;
struct BitMapHeader bmhd;
BPTR iffhandle;

struct DisplayIDInformation *dinfo;

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 )
	{
	Close( iffhandle );
	goto end;
	}

form_length = ReadLong();

if ( ReadLong()!=ID_ILBM )
	{
	Close( iffhandle );
	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;
			break;
		case	ID_CAMG:
			displayID = ReadLong() & CAMGMASK;
			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 ) ) )
				goto end;
			
			if ( bmhd.bmh_Compression )
				iff_loaded = ReadByteRun1( chunk_length );
			else
				iff_loaded = ReadUncompressedFile();

			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;
}


struct TagItem tl[] = {
	{ SA_DisplayID, NULL },
	{ SA_Depth, 0 },
	{ SA_Height, 0 },
	{ SA_Width, 0 },
	{ TAG_END } };

void BlankAndPlay( char *modname, char *filename )
{
struct Screen *scr[2];
Module *mod;
BOOL result, playing = FALSE;
UBYTE brightness = GETBRIGHTNESS( dinfo ), *equilizers, actscr = 1;

if ( mod = OpenModule( modname ) )
	{
	tl[0].ti_Data = DISPLAYID( dinfo );
	if ( result = ( filename ? DecodeILBM( filename ) : FALSE ) )
		{
		tl[1].ti_Data = bmhd.bmh_Depth;
		tl[2].ti_Data = bmhd.bmh_Height / vframes;
		tl[3].ti_Data = ( bmhd.bmh_Width / frames ) << 2;
		}
	
	if ( scr[0] = OpenScreenTagList( NULL, tl ) )
		{
		if ( result ? (BOOL)(scr[1] = OpenScreenTagList( NULL, tl )) : TRUE )
			{
			SpritesOff();

			equilizers = GetEquilizers( mod );

			if ( result )
				{
				UBYTE *address = iffctable;
				ULONG n, m;
				for ( n = 0; n < color_count; n++ )
					{
					for ( m = 0; m < 2; m++ )
						SetRGB4( &scr[m]->ViewPort, n, (*address>>4)*brightness/100, (*(address+1)>>4)*brightness/100, (*(address+2)>>4)*brightness/100 );
					address += 3;
					}
				}
			else
				SetRGB4( &scr[0]->ViewPort, 0, 0, 0, 0 );

			playing = PlayModule( mod );

			if ( playing )
				{
				if ( iffbmap )
					{
					register int n;
					register UWORD frwidth = bmhd.bmh_Width / frames;
					register UWORD frheight = bmhd.bmh_Height / vframes;
					while ( STILL_BLANKING )
						{
						for ( n = 0; n < 3; n++ )
							WaitTOF();
						for ( n = 0; n < 4; n++ )
							if ( equilizers[n] < frames )
								{
								BltBitMap( iffbmap, equilizers[n] * frwidth, frheight * (n % vframes), scr[actscr]->RastPort.BitMap, frwidth * n, 0, frwidth, frheight, 0xC0, 0xFF, NULL );
								equilizers[n]++;
								}
							else
							if ( equilizers[n] == frames )
								{
								BltBitMap( iffbmap, (frames - 1) * frwidth, frheight * (n % vframes), scr[actscr]->RastPort.BitMap, frwidth * n, 0, frwidth, frheight, 0xC0, 0xFF, NULL );
								equilizers[n]++;
								}
						ScreenToFront( scr[actscr] );
						SpritesOff();
						actscr ^= 1;
						}
					}
				else
				WaitServerCommand();
				}

			SpritesOn();
			if ( result )
				CloseScreen( scr[1] );
			}
		CloseScreen( scr[0] );
		}
	if ( result )
		DisposeBitMap( iffbmap );
	FreeModule( mod );
	}

if ( !result || !playing )
	SendClientMsg( ACTION_FAILED );
}


void __main( void )
{
char module[256];
char filename[256];
BOOL found = FALSE;

if ( IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library", 37L ) )
	{
	if ( GfxBase = (struct GfxBase *)OpenLibrary( "graphics.library", 37L ) )
		{
		if ( BitMapBase = OpenLibrary( "bitmap.library",0L ) )
			{
			if ( dinfo = OpenCommunication() )
				{
				if ( GetArgString( dinfo->di_Args, "FILE", filename ) )
					{
					if ( GetArgInt( dinfo->di_Args, "FRAMES", &frames ) )
						found = TRUE;
					if ( !GetArgInt( dinfo->di_Args, "VFRAMES", &vframes ) )
						vframes = 1;
					}
				if ( !found )
					{
					strcpy( filename, "ILBM/PT_Frames.BRS" );
					frames = 6;
					}
				if ( GetArgString( dinfo->di_Args, "MODULE", module ) )
					BlankAndPlay( module,frames > 1 ? filename : NULL );
				else
					SendClientMsg( ACTION_FAILED );
				CloseCommunication( dinfo );
				}
			CloseLibrary( BitMapBase );
			}
		CloseLibrary( (struct Library *)GfxBase );
		}
	CloseLibrary( (struct Library *)IntuitionBase );
	}
}
