/*
  Copyright (C) 1999 E. H. Haley

  YIQ color space

  read jpeg, user-picked
  2D daub4 transform
  keep that coeffs array around forever.

  loop:

  when prefs change (YIQ WCoeff thresholds), copy coeffs mod zeroings
  to a scratch array, tx back, and draw from that.

  hey! glut got menus!

  Also, got rid of some getting-around-unfindable(found)-typo scratch
  array copying/reordering.  Not much faster, though.

  Next: find the top M of N=65535ish entries -- what coefficient and
  what value.  maybe for _demo, get a rank matrix, etc., & sort all of
  them so you can zero them one at a time in order by hitting e.g. y
  or Y, etc.  ONE?? that'd take forever.  Maybe it's time to read
  about GTK.  Okay, for now just print out top M coeffs of N: which
  and value.

 */

#include <GL/glut.h>
#include <X11/Xlib.h>
#include <stdlib.h>
#include <stdio.h>
#include "wto.h"
#include <jpeglib.h>
#include "loadj.h"
#include "color.h"

int w,h,firsttime=1,changed=0;
float fac[3]={1.0,1.0,1.0};
JSAMPLE *arr;
float *coeffs;
char *filename;


void init(int aardc, char **aardv)
{
  int i;

  filename=*(aardv+1);
  glClearColor(0.0,0.0,0.0,1.0);
  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

  if (aardc>1)
    {
      arr=ljf(filename,&w,&h);
            
      coeffs=(float *)calloc(3*w*h,sizeof(float));

      for(i=0; i<w*h; i++)
	rgb256yiq(arr+3*i,coeffs+3*i);
      wtc(coeffs, (unsigned long) w, (unsigned long) h,
	    0,0,w,h,
	    1,daub4);
    }
  else
    { printf("Usage: jwyi [filename]\n"); exit(0); } 
}





void idle(void)
{
  int i,c, zeroed, nonz;
  float *scratch, avg=0.0, max=0.0;

  if(firsttime==1)
    {
      firsttime=0;     //arr is correct--original still
      printf("\nOriginal image\n");
    }
  else if(changed==1)
    {
      changed=0;
      scratch=(float *)calloc(3*w*h,sizeof(float));
      
      for(i=0; i<3*w*h; i++)
	scratch[i]=coeffs[i];

      printf("\nfacY=%.2f, facI=%.2f, facQ=%.2f\n",fac[0],fac[1],fac[2]);
      nonz=3*w*h;
      for (c=0; c<3; c++)
	{
	  avg=max=0.0;
	  zeroed=0;
	  for (i=0; i<w*h; i++)
	    {
	      if(scratch[3*i+c]>max) max=scratch[3*i+c];
	      //	      avg +=fabs(scratch[3*i+c]);
	      avg+=(scratch[3*i+c]>0?scratch[3*i+c]:-scratch[3*i+c]);
	    }
	  avg/=w*h;
	  for (i=0; i<w*h; i++)
	    //	    if(fabs(scratch[3*i+c])<  fac[c]* avg)
	    if((scratch[3*i+c]<fac[c]*avg)&&(-scratch[3*i+c]<fac[c]*avg))
	      {
		zeroed++;
		nonz--;
		scratch[3*i+c]=0.0;
	      }
	  printf("c=%d: avg=%f, max=%f, zeroed=%d\n",c,avg,max,zeroed);
	}
      printf("nonzeroed=%d\n",nonz);

      wtc(scratch, (unsigned long) w, (unsigned long) h,
	    0,0,w,h,
	    -1,daub4);
      for(i=0; i<w*h; i++)
	yiq256rgb(scratch+3*i,arr+3*i);  
      
      free(scratch);
    }
  else return;

  glutPostRedisplay();
}

void display(void)
{
  glDrawPixels(w,h, GL_RGB, GL_UNSIGNED_BYTE, arr);
  glutSwapBuffers();
}

void mouse(int button, int state, int x, int y)
{
  if ((button==GLUT_LEFT_BUTTON)&&(state==GLUT_UP))
    {
      free(arr);
      free(coeffs);
      exit(0);
    }
}

void menu(int value)
{
  changed=1;
}
void menuY(int value)
{
  changed=1;
  switch((char)value)
    {
    case 1:
      fac[0]*=10.0;
      break;
    case 2:
      fac[0]*=2.0;
      break;
    case 3:
      fac[0]*=1.1;
      break;
    case 4:
      fac[0]/=1.1;
      break;
    case 5:
      fac[0]/=2.0;
      break;
    case 6:
      fac[0]/=10.0;
      break;
    case 7:
      fac[0]=1.0;
      break;
    case 8:
      fac[0]=10.0;
      break;
    case 9:
      fac[0]=100.0;
      break;
    case 10:
      fac[0]=1000.0;
      break;
    case 11:
      fac[0]=10000.0;
      break;
    }
}
void menuI(int value)
{
  changed=1;
  switch((char)value)
    {
    case 1:
      fac[1]*=10.0;
      break;
    case 2:
      fac[1]*=2.0;
      break;
    case 3:
      fac[1]*=1.1;
      break;
    case 4:
      fac[1]/=1.1;
      break;
    case 5:
      fac[1]/=2.0;
      break;
    case 6:
      fac[1]/=10.0;
      break;
    case 7:
      fac[1]=1.0;
      break;
    case 8:
      fac[1]=10.0;
      break;
    case 9:
      fac[1]=100.0;
      break;
    case 10:
      fac[1]=1000.0;
      break;
    case 11:
      fac[1]=10000.0;
      break;
    }
}
void menuQ(int value)
{
  changed=1;
  switch((char)value)
    {
    case 1:
      fac[2]*=10.0;
      break;
    case 2:
      fac[2]*=2.0;
      break;
    case 3:
      fac[2]*=1.1;
      break;
    case 4:
      fac[2]/=1.1;
      break;
    case 5:
      fac[2]/=2.0;
      break;
    case 6:
      fac[2]/=10.0;
      break;
    case 7:
      fac[2]=1.0;
      break;
    case 8:
      fac[2]=10.0;
      break;
    case 9:
      fac[2]=100.0;
      break;
    case 10:
      fac[2]=1000.0;
      break;
    case 11:
      fac[2]=10000.0;
      break;
    }
}

int main(int aardc, char **aardv)
{
  int smY, smI, smQ;

  init(aardc, aardv);
  glutInit(&aardc, aardv);

  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA );
  glutInitWindowSize(w,h);
  glutCreateWindow(aardv[0]);
  glutDisplayFunc(display);
  glutMouseFunc(mouse);
  glutIdleFunc(idle);

  smY=glutCreateMenu(menuY);
  glutAddMenuEntry("x10",1);
  glutAddMenuEntry("x2",2);
  glutAddMenuEntry("x1.1",3);
  glutAddMenuEntry("/1.1",4);
  glutAddMenuEntry("/2",5);
  glutAddMenuEntry("/10",6);
  glutAddMenuEntry("Reset to 1.0",7);
  glutAddMenuEntry("Set to 10.0",8);
  glutAddMenuEntry("Set to 100.0",9);
  glutAddMenuEntry("Set to 1000.0",10);
  glutAddMenuEntry("Set to 10000.0",11);


  smI=glutCreateMenu(menuI);
  glutAddMenuEntry("x10",1);
  glutAddMenuEntry("x2",2);
  glutAddMenuEntry("x1.1",3);
  glutAddMenuEntry("/1.1",4);
  glutAddMenuEntry("/2",5);
  glutAddMenuEntry("/10",6);
  glutAddMenuEntry("Reset to 1.0",7);
  glutAddMenuEntry("Set to 10.0",8);
  glutAddMenuEntry("Set to 100.0",9);
  glutAddMenuEntry("Set to 1000.0",10);
  glutAddMenuEntry("Set to 10000.0",11);


  smQ=glutCreateMenu(menuQ);
  glutAddMenuEntry("x10",1);
  glutAddMenuEntry("x2",2);
  glutAddMenuEntry("x1.1",3);
  glutAddMenuEntry("/1.1",4);
  glutAddMenuEntry("/2",5);
  glutAddMenuEntry("/10",6);
  glutAddMenuEntry("Reset to 1.0",7);
  glutAddMenuEntry("Set to 10.0",8);
  glutAddMenuEntry("Set to 100.0",9);
  glutAddMenuEntry("Set to 1000.0",10);
  glutAddMenuEntry("Set to 10000.0",11);


  glutCreateMenu(menu);
  glutAddSubMenu("Y",smY);
  glutAddSubMenu("I",smI);
  glutAddSubMenu("Q",smQ);
  glutAttachMenu(GLUT_RIGHT_BUTTON);

  glutMainLoop();
  exit(0);
}

