/* This example use of imageio.library loads the image file specified
		on the command line and views it halved in size on a cybergraphics
		screen. It also demonstrates the use of a progress indicator
		callback hook.

		Uncomment the display module you need on line 97 (currently guigfx).
*/

#include <stdio.h>

#include <dos/dos.h>
#include <exec/memory.h>
#include <exec/types.h>

#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/cybergraphics_protos.h>
#include <clib/intuition_protos.h>

#include <pragmas/dos_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#include <pragmas/cybergraphics_pragmas.h>

#include <cybergraphics/cybergraphics.h>

#include <imageio/imageio.h>
#include <imageio/imageio_protos.h>
#include <imageio/imageio_pragmas.h>

#include <guigfx/guigfx.h>
#include <pragmas/guigfx_pragmas.h>
#include <guigfx/guigfx_protos.h>

/* Function prototypes */
__saveds __asm ULONG progressFunc( register __d0 ULONG curr, register __d1 ULONG lines, register __a0 void *userdata );
void DisplayCyberGfx( UBYTE *buffer, UBYTE cs, ULONG rs, ULONG x, ULONG y );
void DisplayGuiGfx( UBYTE *buffer, UBYTE cs, ULONG rs, ULONG x, ULONG y );

extern struct Library *DOSBase;
struct Library *ImageIOBase, *IntuitionBase;

void main( int argc, char **argv )
{
	ImageIOBase = OpenLibrary( "imageio.library", 2 );
	IntuitionBase = OpenLibrary( "intuition.library", NULL );
	if ( IntuitionBase && ImageIOBase )
	{
		struct ImageHandle *ih;
		ULONG err;
		BPTR fp;

		fp = Open( argv[1], MODE_OLDFILE );
		if ( fp != NULL )
		{
			err = AllocImage( &ih,
				IMG_SrcFile, fp,
				TAG_DONE );
			if ( !err )
			{
				ULONG num = 1, denom = 2;
				ULONG x, y, bpp, rs;
				UBYTE *buffer, cs, it;

				err = GetImageAttrs( ih,
					IMG_ImageType, &it,
					TAG_DONE );
				if ( !err )
				{
					printf("Image type=%d\n",it);
				}

				err = GetImageAttrs( ih,
					IMG_Width, &x,
					IMG_Height,&y,
					IMG_BytesPerPixel, &bpp,
					IMG_ColourSpace, &cs,
					IMG_RowSize, &rs,
					IMG_TestScaleNum, num,
					IMG_TestScaleDenom, denom,
					TAG_DONE );
				if ( !err )
				{
					printf( "width=%ld, height=%ld\n", x, y );
					printf( "bytes per pixel=%ld, colourspace=%d\n", bpp, cs );
					printf( "row size=%ld\n", rs );

					err = ReadImage( ih,
						IMG_ScaleNum, num,
						IMG_ScaleDenom, denom,
						IMG_ImageBuffer, &buffer,
						IMG_ProgressHook, progressFunc,
						TAG_DONE );
					if ( !err )
					{
						/* Display image  - uncomment the line you need */
//						DisplayCyberGfx( buffer, cs, rs, x, y );
						DisplayGuiGfx( buffer, cs, rs, x, y );
					}
					else printf( "read image error:%d\n", err );
				}
				else printf( "get image attrs error:%d\n", err );

				FreeImage( ih );
			}
			else printf( "alloc image error:%d\n", err );

			Close( fp );
		}
		else printf( "cant open file\n" );
	}

	if ( ImageIOBase ) CloseLibrary( ImageIOBase );
	if ( IntuitionBase ) CloseLibrary ( IntuitionBase );
}

__saveds __asm ULONG progressFunc( register __d0 ULONG curr, register __d1 ULONG lines, register __a0 void *userdata )
{
	static int prevpercent = 0;

	int percent = ( curr * 100 ) / lines;

	if ( prevpercent != percent )
	{
		if ( percent % 10 == 0 ) printf( "%d%%\n", percent );
	}

	prevpercent = percent;

	return NULL;
}

void DisplayCyberGfx( UBYTE *buffer, UBYTE cs, ULONG rs, ULONG x, ULONG y )
{
	struct CyberGfxBase *CyberGfxBase = NULL;
	ULONG DisplayID;
	struct Screen *scr;
	struct Window *win;
	struct Message *msg;

	CyberGfxBase = (struct CyberGfxBase *)OpenLibrary( "cybergraphics.library", 0L );
	if ( CyberGfxBase )
	{
		DisplayID = BestCModeIDTags( CYBRBIDTG_NominalWidth, 640,
			CYBRBIDTG_NominalHeight, 480,
			CYBRBIDTG_Depth, 24,
			TAG_DONE );

		if ( DisplayID != INVALID_ID )
		{
			scr = OpenScreenTags( NULL,
				SA_Title, "Proof",
				SA_DisplayID, DisplayID,
				SA_Depth, GetCyberIDAttr( CYBRIDATTR_DEPTH, DisplayID ),
				TAG_DONE );

			if ( scr != NULL )
			{
				win = OpenWindowTags( NULL,
					WA_Title, "Proof",
					WA_Flags, WFLG_ACTIVATE | WFLG_SIMPLE_REFRESH |
						WFLG_SIZEGADGET | WFLG_RMBTRAP | WFLG_DRAGBAR |
						WFLG_DEPTHGADGET | WFLG_CLOSEGADGET,
					WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW |
						IDCMP_SIZEVERIFY | IDCMP_NEWSIZE | IDCMP_RAWKEY,
					WA_Left, 16,
					WA_Top, scr->BarHeight+16,
					WA_Width, x,
					WA_Height, y,
					WA_CustomScreen, scr,
					TAG_DONE );

				if ( win != NULL )
				{
					UBYTE format = RECTFMT_RGB;

					switch ( cs )
					{
						case IRCS_UNKNOWN:
						case IRCS_GREY:
							format = RECTFMT_GREY8;
						break;
					}

					WritePixelArray( buffer, 0, 0, rs, win->RPort, 0, 0, x, y, format );

					Wait( 1L << win->UserPort->mp_SigBit );
					while ( ( msg = GetMsg( win->UserPort ) ) != NULL ) ReplyMsg( msg );

					CloseWindow( win );
				}
				else printf( "failed to open window\n" );

				CloseScreen( scr );
			}
			else printf( "failed to open screen\n" );
		}
		else printf( "failed to get display id\n" );
	}
	else printf( "failed to open cybergfx.library\n" );

	if ( CyberGfxBase ) CloseLibrary ( (struct Library *)CyberGfxBase );
}

void DisplayGuiGfx( UBYTE *buffer, UBYTE cs, ULONG rs, ULONG x, ULONG y )
{
	struct Library *GuiGFXBase;

	GuiGFXBase = OpenLibrary( "guigfx.library", NULL );
	if ( GuiGFXBase )
	{
		struct Window *win;
		APTR dh, pi;
		UBYTE *argb;

		win = OpenWindowTags( NULL,
			WA_Title, "Proof",
			WA_Flags, WFLG_ACTIVATE | WFLG_SIMPLE_REFRESH |
				WFLG_SIZEGADGET | WFLG_RMBTRAP | WFLG_DRAGBAR |
				WFLG_DEPTHGADGET | WFLG_CLOSEGADGET,
			WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW |
				IDCMP_SIZEVERIFY | IDCMP_NEWSIZE | IDCMP_RAWKEY,
			WA_Left, 16,
			WA_Top, 16,
			WA_Width, x,
			WA_Height, y,
			TAG_DONE );

		if ( win != NULL )
		{
			dh = ObtainDrawHandle( NULL, win->RPort, win->WScreen->ViewPort.ColorMap, TAG_DONE );

			if ( dh )
			{
				argb = AllocVec( x * y * 4, MEMF_PUBLIC | MEMF_CLEAR );

				if ( argb )
				{
					int i, count = 0;
					char **dest;

					/* Convert an RGB buffer to an ARGB buffer setting A to 0.*/
					dest = (char **)argb;

					for ( i = 0; i < x * y * 3; i += 3 )
					{
						dest[count++] = (char *)( ( (ULONG) * (char**)&buffer[i] ) >> 8 );
					}

					pi = MakePicture( argb, x, y, GGFX_PixelFormat, PIXFMT_0RGB_32, TAG_DONE );

					if ( pi )
					{
						struct Message *msg;

						DrawPicture( dh, pi, 0, 0, NULL );

						Wait( 1L << win->UserPort->mp_SigBit );

						while ( ( msg = GetMsg( win->UserPort ) ) != NULL ) ReplyMsg( msg );

						DeletePicture( pi );
					}
					else printf( "failed to create picture\n" );

					FreeVec( argb );
				}
				else printf( "failed to allocate argb buffer\n" );

				ReleaseDrawHandle( dh );
			}
			else printf( "failed to get drawhandle\n" );

			CloseWindow( win );
		}
		else printf( "failed to open window\n" );
	}
	else printf( "failed to open guigfx.library\n" );

	if ( GuiGFXBase ) CloseLibrary( GuiGFXBase );
}
