/* 
   Copyright (C) 1999 E. H. Haley
   
   treeage() goes with snatches() in that sn writes a data file of
   tiles (fname, score, exp) and that's what treeage reads.  (Used to
   be matches wrote whole nodes and triage read those.)
   
   treeedge is the first attempt to blend the layers.  As each is
   drawn, the pixels from it get * by a sin^2(x)*sin^2(y) at the
   appropriate frequency to deemphasize the edges of tiles (smoothly
   zero their contribution).
   
   Hey, the accidental sin^4(x)*sin^0(y) was pretty cool too,
   suggesting that just a straight blend would be of some interest.
   
   Then try weighting each tile by its score.

 */

#include <stdio.h>
#include <stdlib.h>
#include <jpeglib.h>
#include "lib/loadj.h"
#include <GL/glut.h>
#include <X11/Xlib.h>
#include "lib/tile.h"
#include <math.h>

int dw,dh;
tile *dcont; //display_contender
tfile tatch;
float *sin2;
int nlayers;
int *amp;

void init(int aardc, char **aardv)
{
  int check, i,j,k,level, side, logw, w,h,c;
  FILE *matchfile;
  JSAMPLE *fg;

  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  glReadBuffer(GL_FRONT);

  if (aardc<2) exit(0);
  if ((matchfile=fopen(*++aardv,"r"))==NULL)
    { fprintf(stderr, "can't open %s\n",*aardv); exit(1); }

  check=fread(&tatch,sizeof(tfile),1,matchfile);
  printf("%d\n",tatch.nnodes);
  side=dw=dh=tatch.side;

  dcont=(tile *)malloc(tatch.nnodes*sizeof(tile));
  check=fread(dcont,tatch.nnodes*sizeof(tile),1,matchfile);
  fclose(matchfile);

  //modulate sine strength with foregroundness: less score let tile
  //content show through better; heavy score for target.
  //for this image we'll cheatwise get FGness from the luminance of the
  //original.

  //  fg = rjf(tatch.fname, &w, &h, &c);
  fg = rjf("../../AF512.jpg", &w, &h, &c);

  //create sin2[log dw - log 16 +1][w*h]
  //e.g. log 512 - log 16 + 1 = 9 - 4 + 1 = log512 -3.
  logw = 0;
  while((side>>=1)>0) logw++;
  nlayers=logw-3;

  //Cheat-- declaring here as elsewhere that the minimum side I'll tile
  //is 16 pixels
  //this is silly-- just call sin for a whole period and copy the rest.

  sin2=(float *)malloc(nlayers*dw*dh *sizeof(float));
  for(i=0; i<dw; i++)
    for(j=0; j<dh; j++)
      for(level=0; level<logw-3; level++)
	{
	  sin2[dw*(dh*level +j) +i]
	    //this is sin x * sin y
	    = sin(M_PI*i/(16.0*(1<<level)))
	    * sin(M_PI*j/(16.0*(1<<level)));
	  sin2[dw*(dh*level +j) +i] *= sin2[dw*(dh*level +j) +i];

	  //	  sin2[dw*(dh*level +j) +i] /= 1.6; //was 1,2,1.3
	  //now between 0.0 & 0.75 	  //should be a softer falloff
	  
	  sin2[dw*(dh*level +j) +i] *= (1.0 - (float)fg[3*(dw*j+i)]/256.0);
	  //25_6_ means never zero(?).

	  //	  sin2[dw*(dh*level +j) +i] += 0.1; //was 0,0.25,0.1

	}

  amp=(int *)malloc(nlayers*sizeof(int));
  for (i=0; i<nlayers; i++)
    amp[i]=nlayers-i; //nlayers downto one.


  free(fg);


}


void display(void)
{
  int p,w,h,c, x,y, l,i,j,k, check, zint,exp, level, temp;
  float zoom;
  JSAMPLE *arr, *blayer;
  float *norm, *total;
  //  int *score;

  blayer=(JSAMPLE *)malloc(3*dw*dh*sizeof(JSAMPLE));
  norm=(float *)calloc(3*dw*dh, sizeof(float));
  total=(float *)calloc(3*dw*dh, sizeof(float));
  //  score=(int *)malloc(dw*dh*nlayers* sizeof(int));
  
  p=-1;
  level= nlayers;
  for(l=1; l>0; l<<=1) //forever
    {
      level--;
      for(i=0; i<l; i++)
	for(j=0; j<l; j++)
	  {
	    if (++p>=tatch.nnodes)
	      {
		for(i=0; i<dw; i++)
		  for(j=0; j<dh; j++)
		    for(k=0; k<3; k++)
		      blayer[3*(dw*j+i)+k]
			= (JSAMPLE)(total[3*(dw*j+i)+k] / 
				    (norm[dw*j+i] + 0.01));
		glPixelZoom(1.0,1.0);
		glRasterPos2i(0,0);
		glDrawPixels(dw,dh, GL_RGB, GL_UNSIGNED_BYTE, blayer);
		glFlush();
		
		free(norm); free(total); free(blayer); //free(score);
		return; 
	      }
	    
	    exp = dcont[p].exp;
	    zint = 1 << (exp>0 ? exp : -exp);
	    zoom = exp>0 ? (float)zint : 1.0/(float)zint;
	    glPixelZoom(zoom,zoom);
	    glRasterPos2i(i*dw/l, j*dh/l);
	    
	    if((arr=rjf(dcont[p].fname,&w,&h,&c))!=NULL)
	      glDrawPixels(w,h, c<2?GL_LUMINANCE:GL_RGB,GL_UNSIGNED_BYTE,arr);
	    
	    /*
	    for(x=i*dw/l; x<(i+1)*dw/l; x++)
	      for(y=j*dh/l; y<(j+1)*dh/l; y++)
		{
		  score[dw*(dh*level+y)+x] =1;
		  temp=1;
		  while((temp<<=2) < dfg[3*(dw*y+x)])
		    score[dw*(dh*level+y)+x] *= dcont[p].score;
		  //sort of score to the half log value--!!
		}
	    */
	    printf("p=%d; f=%s; orig w=h=%d; want=%d; exp=%d; score=%d\n",
		   p,
		   dcont[p].fname, 
		   w,
		   dw/l,
		   dcont[p].exp,
		   dcont[p].score);
	    
	    fflush(stdout);
	    free(arr);
	  }
      glReadPixels(0,0,dw,dh,
		   GL_RGB, GL_UNSIGNED_BYTE,
		   blayer);
      
      for(i=0; i<dw; i++)
	for(j=0; j<dh; j++)
	  {
	    for(k=0; k<3; k++)
	      {
		total[3*(dw*j +i)+k]
		  += (float) blayer[3*(dw*j +i)+k]
		  * sin2[dw*(dh*level +j) +i]
		  / amp[level]
		  //		  * score[dw*(dh*level+j)+i];
		  ;
	      }
	    norm[dw*j +i] +=
	      sin2[dw*(dh*level +j) +i]
	      / amp[level];
	      //	    * score[dw*(dh*level+j)+i];
	  }
 
   }      
  
}

  
void mouse(int button, int state, int x, int y)
{
  free(sin2);
  free(dcont);
  //  free(dfg);
  free (amp);
  exit(0);
}


int main(int aardc, char **aardv)
{
  init(aardc, aardv);
  glutInit(&aardc, aardv);

  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
  glutInitWindowSize(dw,dh);
  glutCreateWindow(aardv[0]);
  glutDisplayFunc(display);
  glutMouseFunc(mouse);

  glViewport(0,0, (GLfloat)dw,(GLfloat)dh);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluOrtho2D(0.0, (GLfloat)dw, 0.0, (GLfloat)dh);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  glutMainLoop();
  exit(0);
}


