/*
 * file:     image.c
 * author:   Wes Barris
 * date:     10/19/93
 * purpose:  handles image drawing
 *
 * copyright info:
 *
 *                           @Copyright 1993
 *      Research Equipment Inc. dba Minnesota Supercomputer Center
 *
 * RESTRICTED RIGHTS LEGEND
 *
 * Use, duplication, or disclosure of this software and its documentation
 * by the Government is subject to restrictions as set forth in subdivision
 * { (b) (3) (ii) } of the Rights in Technical Data and Computer Software
 * clause at 52.227-7013.
 */

#include "icop.h"
#include "proto.h"
#include <gl/gl.h>
#include <X11/StringDefs.h>
#include <X11/Xirisw/GlxMDraw.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/ToggleB.h>

extern ICOP	icop;
extern Widget	imageType[5];
extern Widget	standard[2];
extern int	havefile;


static GLXconfig glxConfig [] = {
    { GLX_NORMAL, GLX_RGB, TRUE },
    { 0, 0, 0 }
};


/*
 * Given the original image buf, this routine will compute the legal,
 * illegal, and corrected image bufs.
 */
void
FillImageBuffs(void)
{
   char		str[128];
   double	yy, i, q, y_new, i_new, q_new;
   int		r, g, b;
   int		x, y, iptr;
   int		r_out, g_out, b_out;
   int		ntsc;
   int		high, low, ret;

   high = low = 0;
   ntsc = XmToggleButtonGetState(standard[0]);
   BusyCursorCB((Widget)NULL, (XtPointer)NULL, (char *)NULL);
   for(y=0; y<icop.image.height; y++) {
      for (x=0; x<icop.image.width; x++) {
         r = icop.image.origbuf[y*icop.image.width+x] & 0xff;
         g = icop.image.origbuf[y*icop.image.width+x] >> 8 & 0xff;
         b = icop.image.origbuf[y*icop.image.width+x] >> 16 & 0xff;
/*
 * Convert to YIQ (YUV) color space.
 */
         if (ntsc)
            rgbtoyiq(r, g, b, &yy, &i, &q);
         else /* if standard == PAL */
            rgbtoyuv(r, g, b, &yy, &i, &q);
/*
 * Determine which colors are legal.
 */
         iptr = y*icop.image.width + x;
         if (ntsc) {
            ret = make_legal_yiq(yy, i, q, &y_new, &i_new, &q_new);
            if (ret) {
               yiqtorgb(y_new, i_new, q_new, &r_out, &g_out, &b_out);
               icop.image.legalbuf[iptr] = 0;
               icop.image.illegalbuf[iptr] = r | g << 8 | b << 16 | 255 << 24;
               icop.image.correctedbuf[iptr] = r_out | g_out<<8 | b_out<<16 | 255<<24;
               if (havefile == IMAGE_FILE) {
                  if (ret > 0)
                     high++;
                  else
                     low++;
                  }
               }
            else {
               icop.image.legalbuf[iptr] = r | g << 8 | b << 16 | 255 << 24;
               icop.image.illegalbuf[iptr] = 0;
               icop.image.correctedbuf[iptr] = 0;
               }
            }
         else { /* if pal */
            ret = make_legal_yuv(yy, i, q, &y_new, &i_new, &q_new);
            if (ret) {
               yuvtorgb(y_new, i_new, q_new, &r_out, &g_out, &b_out);
               icop.image.legalbuf[iptr] = 0;
               icop.image.illegalbuf[iptr] = r | g << 8 | b << 16 | 255 << 24;
               icop.image.correctedbuf[iptr] = r_out | g_out<<8 | b_out<<16 | 255<<24;
               if (havefile == IMAGE_FILE) {
                  if (ret > 0)
                     high++;
                  else
                     low++;
                  }
               }
            else {
               icop.image.legalbuf[iptr] = r | g << 8 | b << 16 | 255 << 24;
               icop.image.illegalbuf[iptr] = 0;
               icop.image.correctedbuf[iptr] = 0;
               }
            }
         }
      if (havefile == ASCII_MAP || havefile == BINARY_MAP) {
         if (ret > 0)
            high++;
         else if (ret < 0)
            low++;
         }
      }
   UnBusyCursorCB((Widget)NULL, (XtPointer)NULL, (char *)NULL);
   if (havefile == IMAGE_FILE)
      sprintf(str, "Saturation Limit:\n%d pixels were above\n%d pixels were below", high, low);
   else
      sprintf(str, "Saturation Limit:\n%d colors were above\n%d colors were below", high, low);
   LabelSetString(str);
}


/*
 * This routine is used to initialize a glx widget.  It only has to set the
 * viewport so it can also be used for resizing.
 */
void
InitImageCB(Widget w, XtPointer client_data, char *call_data)
{
   switch (((GlxDrawCallbackStruct *)call_data)->reason) {
      case GlxCR_GINIT:
      case GlxCR_RESIZE:
         GLXwinset(XtDisplay(w), ((GlxDrawCallbackStruct *)call_data)->window);
         viewport(0, (Screencoord)((GlxDrawCallbackStruct *)call_data)->width-1,
                  0, (Screencoord)((GlxDrawCallbackStruct *)call_data)->height-1);
         /*ortho2(-0.5, -0.5,
                ((GlxDrawCallbackStruct *)call_data)->width-0.5,
                ((GlxDrawCallbackStruct *)call_data)->height-0.5);*/
         break;
      default:
         fprintf(stderr, "WARNING -- Unknown reason in InitImageCB.\n");
      }
}

/*
 * This routine will draw the icop background.
 */
void
ShowImageCB(Widget w, XtPointer client_data, char *call_data)
{
   XEvent	event_return;
   short	cv[3];

   if (!icop.image.legalbuf)
      return;
   while (XCheckWindowEvent(XtDisplay(w),
          XtWindow(w),
          ExposureMask, &event_return)) {
      /*printf("Discarded an expose event.\n");*/
      ;
      }

   GLXwinset(XtDisplay(icop.toplevel), XtWindow(w));
   viewport(0, (Screencoord)icop.image.width-1, 0, (Screencoord)icop.image.height-1);
/*
 * Do we already have an initialized data image?
 */
   if (XmToggleButtonGetState(imageType[0]))		/* legal pixels */
      lrectwrite(0, 0, icop.image.width-1, icop.image.height-1,
                 icop.image.legalbuf);
   else if (XmToggleButtonGetState(imageType[1]))	/* illegal pixels */
      lrectwrite(0, 0, icop.image.width-1, icop.image.height-1,
                 icop.image.illegalbuf);
   else if (XmToggleButtonGetState(imageType[2]))	/* corrected pixels */
      lrectwrite(0, 0, icop.image.width-1, icop.image.height-1,
                 icop.image.correctedbuf);
   else if (XmToggleButtonGetState(imageType[3])) {	/* corrected image */
      if (getgdesc(GD_BLEND)) {	/* if blendfunction is supported */
         lrectwrite(0, 0, icop.image.width-1, icop.image.height-1,
                    icop.image.legalbuf);
         blendfunction(BF_SA, BF_MSA);
         lrectwrite(0, 0, icop.image.width-1, icop.image.height-1,
                    icop.image.correctedbuf);
         blendfunction(BF_ONE, BF_ZERO);
         }
      else {
         int i, npix;
         unsigned long *tmpbuf;

         npix = icop.image.width*icop.image.height;
         tmpbuf = (unsigned long *)malloc(npix*sizeof(long));
         for (i=0; i<npix; i++) {
            if (icop.image.correctedbuf[i] & 0xff000000)
               tmpbuf[i] = icop.image.correctedbuf[i];
            else
               tmpbuf[i] = icop.image.origbuf[i];
            }
         lrectwrite(0, 0, icop.image.width-1, icop.image.height-1, tmpbuf);
         free(tmpbuf);
         }
      }
   else if (XmToggleButtonGetState(imageType[4])) {	/* original image */
      lrectwrite(0, 0, icop.image.width-1, icop.image.height-1,
                 icop.image.origbuf);
      }
}


void
ResizeImage(int width, int height)
{
   Arg	args[5];
   int	n;

   if (!icop.image.w)
      icop.image.w = ImageInit(icop.toplevel);
   else {
      n = 0;
      XtSetArg(args[n], XmNwidth, width); n++;
      XtSetArg(args[n], XmNheight, height); n++;
      XtSetValues(icop.image.w, args, n);
      }
}



/*
 * Set the initial preferences.
 */
Widget
ImageInit(Widget parent)
{
   Arg		args[10];
   Widget	imagePanel, glImage;
   int		n;
   short	x, y;
   Dimension	width, height, bwidth;
/*
 * Get the size and location of the main shell.
 */
   n = 0;
   XtSetArg(args[n], XmNx, &x); n++;
   XtSetArg(args[n], XmNy, &y); n++;
   XtSetArg(args[n], XmNwidth, &width); n++;
   XtSetArg(args[n], XmNheight, &height); n++;
   XtSetArg(args[n], XmNborderWidth, &bwidth); n++;
   XtGetValues(icop.toplevel, args, n);
   bwidth = 8;	/* don't know why this doesn't work */
/*
 * Create a separate shell for the image.
 */
   n = 0;
   XtSetArg(args[n], XmNx, x+(short)width+2*(short)bwidth); n++;
   XtSetArg(args[n], XmNy, y); n++;
   /*XtSetArg(args[n], XmNdefaultPosition, False); n++;*/
   imagePanel = XmCreateFormDialog(parent, "imagePanel", args, n);
/*
 * Create a glx widget for the image.
 */
   n = 0;
   XtSetArg(args[n], GlxNglxConfig, glxConfig); n++;
   /*XtSetArg(args[n], XmNtranslations, XtParseTranslationTable("")); n++;*/
   XtSetArg(args[n], XmNwidth, icop.image.width); n++;
   XtSetArg(args[n], XmNheight, icop.image.height); n++;
   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
   glImage = GlxCreateMDraw(imagePanel, "image", args, n);
/*
 * Add some callbacks.
 */
   /*XtAddCallback(glImage, GlxNginitCallback, InitImageCB, 0);*/
   XtAddCallback(glImage, GlxNexposeCallback, ShowImageCB, 0);

   XtManageChild(glImage);
   XtManageChild(imagePanel);
   return glImage;
}
