/*
 *   IMPROV
 *
 *   by Thomas Braunl and Michael Rudolph <braunl@ee.uwa.edu.au>
 *   based on XFQCAM by Paul Chinn <loomer@svpal.org>
 *
 *   QuickCam code by Thomas Davis
 *   Additional QuickCam code Scott Laird <scott@laird.com>
 *   Adapted by Thomas Braunl, Uni Stuttgart, 1996
 *   Color adapted by Thomas Braunl, UWA, 1998
 *
 *   $Id: xdemo.c,v 2.0 1998/02/16 12:08:13 braunl Exp $
 */


#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <forms.h>
#include "xfqcam.h"
#include "controlpanel.h"
#include "qcam.h"
#include "improc.h"


static BYTE  im0[CIMAGE_SIZE];
static BYTE  im1[CIMAGE_SIZE];
static BYTE  * imageBuffer;
static BYTE  images[2][NO_OF_IMAGES+1][CIMAGE_SIZE];


static int iplNOPFlag[NO_OF_IMAGES];
IPLOP iplOps[NO_OF_IMAGES][MAX_IPL_OPS];
int iplCount[NO_OF_IMAGES];
int iplEditCount[NO_OF_IMAGES];

int colgray[NO_OF_IMAGES+1]; /* color AND grayscale */
                               


static char struc[]= { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
static int    diff  = 0;
static int    done  = 0;
static int num_vals = 16;
static int bufferFlag;


extern IPL_CONFIG _IPLConfig;
extern FD_QuickCam * mainwin;
extern BYTE extraImageBuffer[];
extern volatile int stopFlag;


/*
 *    forward declaration of local helper functions
 */

static void InitIPLOps(void);
static void ProcessImage(int imageNumber,
                         int opPos,
                         BYTE * imageIn,
                         BYTE * imageOut,
                         E_IPLOP operation,
                         double * args);



int main(int argc, char ** argv)
{
    int i, j;
    int rc;
    int colCam, camVer, conVer;
    BYTE * opBuffer;

    InitIPLOps();

    _IPLConfig.colorBlack  = 0;
    _IPLConfig.colorWhite  = 15;
    _IPLConfig.imageWidth  = 160;
    _IPLConfig.imageHeight = 120;

    IPL_init(&_IPLConfig);

    rc = QC_init();

    if (rc < 0)
    {
        if (rc == -1)
            fprintf(stderr, "quickcam already in use ?! (remove /tmp/quickcam and try again)\n");
        exit(1);
    }

    if (argc > 1)
        QCAMLoadFile(argv[1]);

    if (QCAMinit(&colCam, &camVer, &conVer) != 0)
    {
        fprintf(stderr, "qcam init failed\n");
        QC_exit();
        exit(1);
    }
    if (colCam) printf("Color camera\n");
      else printf("Grayscale camera\n");

    colgray[0] = _QCConfig.colour;                  /* color or gray */
    for (i=1; i<=NO_OF_IMAGES; i++) colgray[i] = 0; /* gray */

    while(!done)
    {
        QCAMget(&images[bufferFlag][0][0], &diff, &done, colgray[0]);

        if (stopFlag)
            continue;

        fl_clear_browser(mainwin -> FD_LOG_BROWSER);

        imageBuffer = &images[bufferFlag][0][0];
        opBuffer    = &im0[0];

        for (i = 0; i < NO_OF_IMAGES; i++)
	{
            int nopFlag = 1;

            for (j = 0; j < iplCount[i]; j++)
	    {
                if (iplOps[i][j].operation != E_NOP)
		{
                    ProcessImage(i,
                                 j,
                                 imageBuffer,
                                 opBuffer,
                                 iplOps[i][j].operation,
                                 &iplOps[i][j].param[0]);

                    if (opBuffer == &im0[0])
		    {
                        opBuffer = &im1[0];
                        imageBuffer = &im0[0];
		    }
                    else
		    {
                        opBuffer = &im0[0];
                        imageBuffer = &im1[0];
		    }

                    nopFlag = 0;
                    iplNOPFlag[i] = 0;
		}
	    }

            if (nopFlag != 0)
  	    {
                if (iplNOPFlag[i] == 0)
		{
                    memset(&images[bufferFlag][i+1][0], 0, CIMAGE_SIZE);
                    QCAMput(&images[bufferFlag][i+1][0], i+1, 0);
                    colgray[i+1] = 0;
                    iplNOPFlag[i] = 1;
		}
            }
            else
	    {
                memcpy(&images[bufferFlag][i+1][0], imageBuffer, CIMAGE_SIZE);
                QCAMput(imageBuffer, i+1, colgray[i+1]);
	    }
	}

        bufferFlag = 1 - bufferFlag;
    }


    QCAMexit();
    QC_exit();

    exit(0);
}

static void InitIPLOps(void)
{
    int i;

    for (i = 0; i < NO_OF_IMAGES; i++)
    {
        iplCount[i] = 1;
        iplOps[i][0].operation = E_NOP;
    }
}

static void ProcessImage(int imageNumber,
                         int opPos,
                         BYTE * imageIn,
                         BYTE * imageOut,
                         E_IPLOP operation,
                         double * args)
{
  XYDistance distance[128];
  
  
  switch (operation)
  {
  case E_NOP:
    colgray[imageNumber+1] = 0;
    break;
    
    /* color */
  case E_ColGray:
    IPL_col2gray(imageIn, imageOut);
    colgray[imageNumber+1] = 0;
    break;
    
  case E_MatchCol:
    IPL_matchcol(imageIn,imageOut,
		 (BYTE)(args[0]*255),
		 (BYTE)(args[1]*255),
		 (BYTE)(args[2]*255) );
    colgray[imageNumber+1] = 0;
    break;
    
    /* grayscale */
  case E_Laplace:
    IPL_laplace(imageIn, imageOut);
    colgray[imageNumber+1] = 0;
    break;
  case E_Sobel:
    IPL_sobel(imageIn, imageOut);
    colgray[imageNumber+1] = 0;
    break;
  case E_Median:
    IPL_median(imageIn, imageOut);
    colgray[imageNumber+1] = 0;
    break;
  case E_Mean:
    if(colgray[imageNumber]) {
      IPL_mean(imageIn, imageOut);
      colgray[imageNumber+1] = 1;
    } else {
      IPL_mean(imageIn, imageOut);
      colgray[imageNumber+1] = 0;
    }
    break;
  case E_Threshold:
    IPL_threshold(imageIn, imageOut, (BYTE)(args[0] * 16));
    colgray[imageNumber+1] = 0;
    break;
  case E_GrayStretch:
    IPL_gray_stretch(imageIn, imageOut);
    colgray[imageNumber+1] = 0;
    break;
  case E_GrayReduce:
    IPL_gray_reduce(imageIn, imageOut, num_vals);
    colgray[imageNumber+1] = 0;
    break;
  case E_Erosion:
    IPL_erosion(imageIn, imageOut, struc);
    colgray[imageNumber+1] = 0;
    break;
  case E_Dilation:
    IPL_dilation(imageIn, imageOut, struc);
    colgray[imageNumber+1] = 0;
    break;
  case E_Open:
    IPL_open(imageIn, imageOut, struc);
    colgray[imageNumber+1] = 0;
    break;
  case E_Close:
    IPL_close(imageIn, imageOut,struc);
    colgray[imageNumber+1] = 0;
    break;
  case E_Fill:
    IPL_fill(imageIn,
	     imageOut,
	     (int)(args[0] * _IPLConfig.imageWidth),
	     (int)(args[1] * _IPLConfig.imageHeight),
	     struc);
    colgray[imageNumber+1] = 0;
    break;
    
  case E_ShowXY:
    if(opPos == 0) colgray[imageNumber+1] = colgray[imageNumber];
    if(colgray[imageNumber]) {
      IPL_Cshowxy(imageIn,
		  imageOut,
		  (int)(args[0] * (_IPLConfig.imageWidth-1)),
		  (int)(args[1] * (_IPLConfig.imageHeight-1)));
    } else {
      IPL_showxy(imageIn,
		 imageOut,
		 (int)(args[0] * (_IPLConfig.imageWidth-1)),
		 (int)(args[1] * (_IPLConfig.imageHeight-1)));
    }
    break;
    
  case E_Connected:
    IPL_connected(imageIn,
		  imageOut,
		  (int)(args[0] * _IPLConfig.imageWidth),
		  (int)(args[1] * _IPLConfig.imageHeight),
		  struc);
    colgray[imageNumber+1] = 0;
    break;
  case E_Boundary:
    IPL_boundary(imageIn, imageOut, struc);
    colgray[imageNumber+1] = 0;
    break;
  case E_Skeleton:
    IPL_skeleton(imageIn, imageOut, struc);
    colgray[imageNumber+1] = 0;
    break;
  case E_Circles:
    IPL_FindCircles(imageIn, imageOut, &distance[0]);
    colgray[imageNumber+1] = 0;
    break;
  case E_Negation:
    if(colgray[imageNumber]) {
      IPL_Cnegation(imageIn, imageOut);
    } else {
      IPL_negation(imageIn, imageOut);
    }
    colgray[imageNumber+1] = colgray[imageNumber];
    break;
    
  case E_Noise:
    if(colgray[imageNumber]) {
      IPL_Cnoise(imageIn, imageOut, args[0]);
    } else {
      IPL_noise(imageIn, imageOut, args[0]);
    }
    colgray[imageNumber+1] = colgray[imageNumber];
    break;
    
  case E_Difference:
    if(colgray[imageNumber]) {
      IPL_Cdifference(&images[bufferFlag][imageNumber][0],
		     &images[1-bufferFlag][imageNumber][0],
		     imageOut);
    } else {
      IPL_difference(&images[bufferFlag][imageNumber][0],
		     &images[1-bufferFlag][imageNumber][0],
		     imageOut);
    }
    colgray[imageNumber+1] = colgray[imageNumber];
    break;
    
  case E_Min:
    IPL_min(imageIn, imageOut);
    colgray[imageNumber+1] = 0;
    break;
    
  case E_Max:
    IPL_max(imageIn, imageOut);
    colgray[imageNumber+1] = 0;
    break;
    
  case E_Corner:
    IPL_corner(imageIn, imageOut);
    colgray[imageNumber+1] = 0;
    break;
    
  case E_TestPalette:
    IPL_TestPalette(imageOut);
    colgray[imageNumber+1] = 1;
    break;
    
  case E_Overlay:
    if(colgray[0]) {        /* color or gray depends on original camera input */
      IPL_Coverlay(&images[bufferFlag][0][0],
                  imageIn,
                  imageOut,
                  (BYTE)(args[0] * 255),
                  (BYTE)(args[1] * 255),
                  (BYTE)(args[2] * 255));
    } else {
      IPL_overlay(&images[bufferFlag][0][0],
		  imageIn,
		  imageOut,
		  (BYTE)(args[0] * (_IPLConfig.colorWhite-
				    _IPLConfig.colorBlack)));
    }
    colgray[imageNumber+1] = colgray[0]; /* like original camera input */
    break;
    
  case E_Dithering:
    IPL_dither(imageIn, imageOut);
    colgray[imageNumber+1] = 0;
    break;
    
  case E_Region:
    IPL_region_growing(imageIn,
		       imageOut,
		       (BYTE)(args[0] * (_IPLConfig.colorWhite-
					 _IPLConfig.colorBlack)));
    colgray[imageNumber+1] = 0;
    break;
    
  default:
    if(colgray[imageNumber]) {
      IPL_Cidentity(imageIn, imageOut);
    } else {
      IPL_identity(imageIn, imageOut);
    }
    if (opPos == 0) colgray[imageNumber+1] = colgray[imageNumber];
    break;
  }
}


int printf(const char * format, ...)
{
    char temp[1024];
    va_list vargs;
    int count;

    va_start(vargs, format);
    count = vsprintf(temp, format, vargs);
    fl_add_browser_line(mainwin -> FD_LOG_BROWSER, temp);
    va_end(vargs);

    return count;
}

