/*

  File:		ProGrabP4.c
  Author:	Nicholas Redgrave
  Date:		20th September 1998
  Description:	Program to grab video frames using the FG24/ProGrab24RT
		using the Picasso IV PIP window.
  Requirements:	FG24/ProGrab24RT, Picasso IV, prograb.library, ixemul.library
  Environment:	GNU C compiler, WorkBench 3.1

  Contact:	baron@bologrew.demon.co.uk


  AREXX code based on SnoopDOS source.




*/


#include <exec/types.h>
#include <exec/lists.h>
#include <exec/ports.h>
#include <exec/memory.h>

#include <libraries/gadtools.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/gadgetclass.h>
#include <intuition/sghooks.h>
#include <libraries/asl.h>
#include <graphics/displayinfo.h>
#include <resources/misc.h>
#include <graphics/gfxbase.h>


#include <clib/asl_protos.h>
#include <clib/intuition_protos.h>
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/misc_protos.h>
#include <clib/icon_protos.h>
#include <clib/rexxsyslib_protos.h>


#include <rexx/storage.h>
#include <rexx/rxslib.h>
#include <rexx/errors.h>

#include <proto/picasso96.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#include "prograba.h"
#include "prograbi.h"


/* Prototypes */

int main( int argc, char *argv[]);
void MainLoop(void);
int  InitRexxPort(void);
void HandleRexxMsgs(void);
void CleanupRexxPort(void);
int  ProcessRexxMsgs(char *);
long InitStuff( void );
void CleanStuff( void );
void InitPIP(void);
void RenderPIP(void);


#define PORT_NAME  "PROGRAB"
#define REXX_OKAY 0
#define REXX_UNKNOWN 1




char *PubScreenName = "Workbench";
struct Window *wd;
struct RastPort *rp = NULL;
struct RenderInfo RI;





struct Library *P96Base = NULL;
struct Library *ProGrabBase = NULL;
struct Library *GfxBase = NULL;
struct Library *DOSBase = NULL;
struct Library *IntuitionBase = NULL;
struct Library *RexxSysBase;

struct MsgPort *SnoopPort;	/* ARexx message port */
ULONG  RexxPortMask;		/* Sig mask for Rexx msgs	*/
int    QuitFlag;		/* If true, user said quit	*/
int    iPIP = 0;


UBYTE *pmem;
struct EVDigi vdigi;


/* Default Image resolution */
int iGrabFormat = EVDIGI_MODE_LORES;

LONG PIPWidth = 320, PIPHeight = 256;

/*
Header for P6 PPM file "P6,LF,320,LF,256,LF,255"
                       "P6,LF,Width,LF,Height,LF,255"
*/

char cPPMheader[15] = {80,54,10,51,50,48,10,50,53,54,10,50,53,53,10};
char cTmp[4];




FILE *fp;
#ifdef DEBUG
FILE *fp2;
#endif




int main( int argc, char *argv[] )
{
  char *param;
  int i;


#ifdef DEBUG
     fp2=fopen("tmp.tmp","wt");
     if(!fp2) return 30;
#endif


/* Was a command line parameter specified? */
  if( argc <= 1 )
  {
    iGrabFormat = EVDIGI_MODE_LORES;
  }
  else
  {
    param = argv[1];

    if(*param == '0') iGrabFormat = EVDIGI_MODE_LORES;
    if(*param == '1') iGrabFormat = EVDIGI_MODE_LORES_OSCAN;
    if(*param == '2') iGrabFormat = EVDIGI_MODE_HIRES;
    if(*param == '3') iGrabFormat = EVDIGI_MODE_HIRES_OSCAN;
    if(*param == '4') iGrabFormat = EVDIGI_MODE_HIRESLACE;
    if(*param == '5') iGrabFormat = EVDIGI_MODE_HIRESLACE_OSCAN;
    if(*param == '?')
    {
      printf("Usage: prograbr <resolution number>\n");
      printf("0: 320x256 (default)\n");
      printf("1: 368x256\n");
      printf("2: 640x256\n");
      printf("3: 736x283\n");
      printf("4: 640x512\n");
      printf("5: 736x512\n");
      exit(0);
    }
  }




/* Select resolution paramters (change if using NTSC) */


  switch(iGrabFormat)
  {
    case EVDIGI_MODE_LORES:
      PIPWidth  = 320L;
      PIPHeight = 256L;
    break;
    case EVDIGI_MODE_LORES_OSCAN:
      PIPWidth  = 368L;
      PIPHeight = 283L;
    break;
    case EVDIGI_MODE_HIRES:
      PIPWidth  = 640L;
      PIPHeight = 256L;
    break;
    case EVDIGI_MODE_HIRES_OSCAN:
      PIPWidth  = 736L;
      PIPHeight = 283L;
    break;
    case EVDIGI_MODE_HIRESLACE:
      PIPWidth  = 640L;
      PIPHeight = 512L;
    break;
    case EVDIGI_MODE_HIRESLACE_OSCAN:
      PIPWidth  = 736L;
      PIPHeight = 512L;
    break;
  }

/* Patch PPM header */
  sprintf(cTmp,"%ld",PIPWidth);
  memcpy(&cPPMheader[3],cTmp,3);
  sprintf(cTmp,"%ld",PIPHeight);
  memcpy(&cPPMheader[7],cTmp,3);




/* Allocate memory for the required resolution */
     pmem = AllocMem( PIPWidth * PIPHeight * 3, MEMF_ANY|MEMF_CLEAR);
     if(!pmem)
     {
#ifdef DEBUG
       fclose(fp2);
#endif
       return 30;
     }


     if( InitStuff() == 0 )
     {



/* Initialize private structure of the "prograb.library" */
        vdigi.GfxBase = (struct Library *)GfxBase;
        vdigi.DOSBase = (struct Library *)DOSBase;
        vdigi.IntuitionBase = (struct Library *)IntuitionBase;



/* EVDIGI_Init() will automatically detect the PCMCIA interface. */

        EVDIGI_Init(&vdigi);


        /* Check if there is any video signal connected */
        if(! EVDIGI_CheckVideoSignal() )
        {
          printf("No video signal detected\n");
          FreeMem( pmem, PIPWidth * PIPHeight * 3);
          EVDIGI_Cleanup();
          CleanStuff();
          return 10;
        }




/* Now we can change default values for: */
        EVDIGI_SetBrightness(10);     /* default is 0  */
        EVDIGI_SetSaturation(15);     /* default is 10 */
        EVDIGI_SetContrast(11);       /* default is 10 */


/* setup PIP window and AREXX port */
        InitPIP();
        InitRexxPort();





/* wait for commands here */
        MainLoop();

        CleanupRexxPort();

     }

     FreeMem( pmem, PIPWidth * PIPHeight * 3 );


     EVDIGI_Cleanup();
     CleanStuff();


#ifdef DEBUG
     fclose(fp2);
#endif

}


/*
 *	MainLoop()
 *
 *	Processes all incoming events
 */
void MainLoop(void)
{


        QuitFlag = 0;

	while (!QuitFlag)
        {
		ULONG mask;

		mask = Wait(	RexxPortMask | SIGBREAKF_CTRL_C);


		if (mask & RexxPortMask)
                {
#ifdef DEBUG
                  fprintf(fp2,"REXX message received\n");
#endif
                  HandleRexxMsgs();
                }
		if (mask & SIGBREAKF_CTRL_C)
                {
#ifdef DEBUG
                  fprintf(fp2,"CTRL-C received\n");
#endif
                  QuitFlag = 1;
                }
	}

}



/*
 *		InitRexxPort
 *
 *		Attempts to create SnoopDos's public port and initialise SnoopPort
 *		and RexxPortMask accordingly. If the port already exists, still
 *		returns TRUE but SnoopPort will be NULL.
 *
 *		If we can't create the port for some reason, returns FALSE.
 */
int InitRexxPort(void)
{
	struct MsgPort *port;

	Forbid();
	port = FindPort(PORT_NAME);
	if (!port)
        {
		SnoopPort = CreateMsgPort();
		if (!SnoopPort)
                {
			Permit();
			return (FALSE);
		}
		SnoopPort->mp_Node.ln_Name = PORT_NAME;
		SnoopPort->mp_Node.ln_Pri  = 1;	/* Speed up searches */
		AddPort(SnoopPort);
		RexxPortMask = 1 << SnoopPort->mp_SigBit;
	}
	Permit();
	return (TRUE);
}



/*
 *		CleanupRexxPort()
 *
 *		Cleans up our SnoopDos port -- removes it from the public port
 *		list, and then replies to any messages it has outstanding. Call
 *		before exiting.
 */
void CleanupRexxPort(void)
{
	if (SnoopPort) {
		struct RexxMsg *msg;

		Forbid();
		RemPort(SnoopPort);
		while ((msg = (struct RexxMsg *)GetMsg(SnoopPort)) != NULL)
                {
			msg->rm_Result1 = RC_FATAL;
			msg->rm_Result2 = NULL;
			ReplyMsg(msg);
		}
		Permit();
		DeleteMsgPort(SnoopPort);
		SnoopPort = NULL;
	}
}


/*
 *		HandleRexxMsgs()
 *
 *		Handles any new messages at our Rexx port
 */

void HandleRexxMsgs(void)
{
  struct RexxMsg *msg;
  int iret;

  while ((msg = (struct RexxMsg *)GetMsg(SnoopPort)) != NULL)
  {
    msg->rm_Result1 = RC_OK;
    msg->rm_Result2 = NULL;

    if ((msg->rm_Action & RXCODEMASK) == RXCOMM)
    {

/*
 *  Got a valid ARexx message, now process it
 */
      iret = ProcessRexxMsgs(msg->rm_Args[0]);


      if(iret == REXX_OKAY)
      {
        msg->rm_Result1 = RC_OK;
      }
      else
      {
        msg->rm_Result1 = 30;
      }


    }

    ReplyMsg(msg);
  }


}


/*
 *
 * 	ProcessRexxMsgs
 *
 *
 */

int ProcessRexxMsgs(char *cmdline)
{
  long i;


  if(strcmp("QUIT",cmdline) == 0)
  {
#ifdef DEBUG
    fprintf(fp2,"QUIT received\n");
#endif
    QuitFlag = 1;
    return REXX_OKAY;
  }


  if(strcmp("GRAB",cmdline) == 0)
  {
#ifdef DEBUG
    fprintf(fp2,"GRAB received\n");
#endif

/* Now grab an image in required resolution.
   RGB data will be saved from the "pmem" address. */
    if( EVDIGI_CheckVideoSignal() )
    {
      EVDIGI_GrabImage(&vdigi, iGrabFormat, pmem);


/* Write image data to disk */
/* Amount of data to copy depends on resolution used
   e.g. 320 x 256 x 3 bytes = 245760
        736 x 512 x 3 bytes = 1130496
*/

      fp = fopen("ram:tmp.ppm","wb");
      if(fp != NULL)
      {
        fwrite(cPPMheader,1,15,fp);

        for(i=0L; i<(PIPWidth * PIPHeight * 3); i++)
        {
          fwrite(pmem+i,1,1,fp);
        }
      }
      fclose(fp);

/* Render image to PIP */
      if(iPIP) RenderPIP();

    }

    return REXX_OKAY;
  }


  return REXX_UNKNOWN;

}

long InitStuff( void )
{
    DOSBase = OpenLibrary( "dos.library", 37L );
    if( DOSBase == NULL )
        return( 1l );

    IntuitionBase = OpenLibrary("intuition.library", 37L );
    if( IntuitionBase == NULL )
        return( 2l );

    GfxBase = OpenLibrary( "graphics.library", 37L );
    if( GfxBase == NULL )
        return( 1l );


    RexxSysBase = OpenLibrary("rexxsyslib.library",  0);
    if( RexxSysBase == NULL )
        return( 1l );


    ProGrabBase = (struct Library *)OpenLibrary("prograb.library", 0L );
    if( ProGrabBase == NULL )
        return( 3l );

    P96Base = OpenLibrary("Picasso96API.library",2);
    if( P96Base == NULL )
        return( 3l );

     return 0L;
}

void CleanStuff( void )
{


  if(iPIP)
     p96PIP_Close(wd);

  if( P96Base )
     CloseLibrary( P96Base );


  if( ProGrabBase )
     CloseLibrary( ProGrabBase );

  if (RexxSysBase)
     CloseLibrary( (struct Library *)RexxSysBase);

  if( GfxBase )
      CloseLibrary( (struct Library *)GfxBase );

  if( IntuitionBase )
      CloseLibrary( ( struct Library *)IntuitionBase );

  if( DOSBase )
      CloseLibrary( ( struct Library *)DOSBase );

}


void InitPIP(void)
{
  long *plPIPError = 0L;


  if(wd = p96PIP_OpenTags(P96PIP_SourceFormat, RGBFB_R5G5B5,
                          P96PIP_SourceWidth, PIPWidth,
                          P96PIP_SourceHeight, PIPHeight,
                          P96PIP_ErrorCode, plPIPError,
/* these tags are optional, but help */
                          WA_Title, "ProGrabP4 PIP",
                          WA_Activate, FALSE,
                          WA_RMBTrap, TRUE,
                          WA_Width, PIPWidth,
                          WA_Height, PIPHeight,
                          WA_DragBar, TRUE,
                          WA_DepthGadget, TRUE,
                          WA_SimpleRefresh, TRUE,
                          WA_SizeGadget, TRUE,
                          WA_CloseGadget, FALSE,
                          WA_PubScreenName, PubScreenName,
                          TAG_DONE))
  {
    p96PIP_GetTags(wd, P96PIP_SourceRPort, (ULONG)&rp, TAG_END);

    if(rp)
    {
      iPIP = 1;
      RI.Memory      = pmem;
      RI.BytesPerRow = 3*PIPWidth;
      RI.RGBFormat   = RGBFB_R8G8B8;

      p96RectFill(rp, 0,0,PIPWidth, PIPHeight, 0);

    }
    else
    {
      p96PIP_Close(wd);
      iPIP = 0;
    }
  }
  else
  {
    printf("failed to open PIP %ld\n",*plPIPError);
  }


}




void RenderPIP(void)
{



/* This copies the data to the PIP window */

  p96WritePixelArray(&RI,0,0,rp,0,0,PIPWidth,PIPHeight);


#ifdef XXX

/* This is a slow way of doing it */
  for(y=0; y<PIPHeight; y++)
  {
    for(x=0; x<PIPWidth; x++)
    {

      ucRed   = *pLoc++;
      ucGreen = *pLoc++;
      ucBlue  = *pLoc++;

      PixelColour = ucBlue + (256*ucGreen) + (65536L*ucRed);

      p96WritePixel(rp, x, y, PixelColour);

    }
  }
#endif



}



/*************************************************************************/
