/********************************************
 * LINUX centric code
 * To compile and run as is you'll need
 * at least a recent version of libpng which
 * in turn needs a recent version of libz.
 * 
 * *****************************************/

#include "h.h"
#include "mask.h"

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "png.h"

void dump(void);
void smooth_3();
void smooth_4();
void smooth_8();
void smooth_15();
void smooth_16();
void smooth_24();
void smooth_32();

pic_format *grid;
int file_number;

void fill( int x0, int y0, int x1, int y1, double r, double g, double b );
void clean( void );

#define grand() ( drand48()-drand48() )	

#define RM2 (RAND_MAX/2)
/************************
*						*
*						*
************************/
int main( void ) {


	int index;
	register int i,j, ii, jj;
	double r,g,b, scale,t, scale2;
	int depth, tr, th;
	int mid_point;
		
	index =  GRID_WIDTH*GRID_HEIGHT*sizeof( pic_format);
	grid = (pic_format *)malloc(index);
	if( ! grid ) {
		printf("grid malloc failed\n");
	 	exit(0);
	}
	file_number=1000;

	index=0;
	for(i=0; i < GRID_WIDTH; i++ ) {
		for(j=0; j < GRID_HEIGHT; j++ ) {
			grid[index].r =  0.0001;
			grid[index].g =  0.0001;
			grid[index].b =  0.0001;
			index++;
		}
	}
	
    #define DEPTH (GRID_WIDTH/2)
   depth = DEPTH;
	mid_point = 0;
	scale = 2.0;
	while( depth > 1 ) {
	   depth /= 2;
	   printf("depth = %d\nscale = %5.5f\n", (int)depth, scale  );
		/* noise is scaled down per pass */		
	   for(i=0; i < GRID_WIDTH; i+= depth ) {
	      for(j=0; j < GRID_HEIGHT; j+= depth) {
 			 if( rand() > RM2 ) {
				 r = drand48()/scale;
				 g = drand48()/scale;
				 b = drand48()/scale;
				 /* fill a rectangle with  rgb */
				 fill( i, j, i+depth, j+depth, r,g,b );
			 }
	      }
	   }
		/* a sort of mid-point smoothing */
	   if( (depth < 200) && mid_point == 0 ) {
		   smooth_8();
		   mid_point = 1;
	   }
		/* cut the feed back from drand48 down by half */
	   scale*=2.0;
	}
	dump();
	smooth_3();
		
	/* topical noise, in stages */
	th = RAND_MAX/2;
	index = 0;
	for(index=0; index < GRID_WIDTH* GRID_HEIGHT; index++ ) {
	   tr = rand();
	   if( tr > th ) {
	      grid[index].r += drand48();
	      grid[index].g += drand48();
	      grid[index].b += drand48();
	   }
	}

	smooth_32();
	//
	/* more topical noise */
	th = (int)(double)RAND_MAX/1.1;
	index = 0;
	for(index=0; index < GRID_WIDTH* GRID_HEIGHT; index++ ) {
	   tr = rand();
	   if( tr > th ) {
	      grid[index].r += (drand48()*.001);
	      grid[index].g += (drand48()*.001);
	      grid[index].b += (drand48()*.001);
	   }
	}
	//
	/* and another topical noise */	
	th = (int)(double)RAND_MAX/1.05;
	index = 0;
	for(index=0; index < GRID_WIDTH* GRID_HEIGHT; index++ ) {
	   tr = rand();
	   if( tr > th ) {
	      grid[index].r += (drand48()*.0005);
	      grid[index].g += (drand48()*.0005);
	      grid[index].b += (drand48()*.0005);
	   }
	}
	
	end:
	dump();
	free( grid );
	return 1;	
}
/************************
*						*
*						*
************************/
void dump( void ) {
	FILE *f, *rgbeF;
	char name[50];
	register int i,j;
	double scale, rm, gm, bm;
	float *pic_buffer;
	int index, index2;
	rm = gm = bm = -9999999.0009999;
	
	sprintf(name, "h%d.png", file_number );

	index = 0;
	for(i=0;i<GRID_WIDTH; i++) {
		for(j=0;j<GRID_HEIGHT; j++) {	
		  if( grid[index].r > rm ) rm = grid[index].r;
		  if( grid[index].g > gm ) gm = grid[index].g;
		  if( grid[index].b > bm ) bm = grid[index].b;
		  index++;
	   }
	}
	
	printf(" red max = %5.5f green max = %5.5f blue max = %5.5f\n", rm, gm, bm );	
	png_writer( name, grid );
	printf("done writting file: h%d.png\n", file_number);
	file_number++;

	/****
	 * If your have the Radiance sources ....
	 * This writes a pic file
	 * 
	***/
	sprintf(name,"rgbe%d.pic", file_number );
	rgbeF = fopen( name, "wb");
	pic_buffer = (float *)malloc( GRID_WIDTH*GRID_HEIGHT*sizeof(float)*3);
	if( !pic_buffer ) {
		printf("\npic_buffer malloc failed\n");
		return;
	}
	memcpy( pic_buffer, grid,  GRID_WIDTH*GRID_HEIGHT*sizeof(float)*3 );
        RGBE_WriteHeader( rgbeF, GRID_WIDTH, GRID_HEIGHT, NULL );
        RGBE_WritePixels( rgbeF, (float *)pic_buffer, GRID_WIDTH*GRID_HEIGHT );
	free( pic_buffer );
	fclose( rgbeF );
		
}
/************************
*						*
*						*
************************/
void fill( int x0, int y0, int x1, int y1, double r, double g, double b )
{
	register int index,j,i;
	int t;
	
	if( x0 > x1 ) {
		t = x0;
		x0 = x1;
		x1 = t;
	}
	if( y0 > y1 ) {
		t = y0;
		y0 = y1;
		y1 = t;
	}
	if( x1 > GRID_WIDTH ) x1 = GRID_WIDTH;
	if( y1 > GRID_HEIGHT ) y1 = GRID_HEIGHT;
	

	for( i=x0; i<x1; i++ ) {
		for( j=y0; j<y1; j++ ) {
			index = i + ( j * GRID_HEIGHT );
				grid[index].r += r;
				grid[index].g += g;
				grid[index].b += b;
		}
	}
}

/************************
*						*
*						*
************************/
void smooth_32() {
	double rs, gs, bs, ms;
	int i,j;
	register int index,m,n;
	int idx, jdx;


	float NOISE, theta;
	pic_format *pf = (pic_format *)malloc(GRID_WIDTH * GRID_HEIGHT * sizeof( pic_format ));
       if( ! pf ) {
	  printf("\nmalloc faliure in smooth_32. Exiting...\n");
	  free(grid);
	  exit(0);
       }
	
	printf("\nsmooth_32\n");
	//dump();
	for( i=0; i<GRID_HEIGHT; ++i ) {
		for(j=0; j<GRID_WIDTH; ++j ) {
			
			rs = gs = bs  = 0.0;
			for( m=0; m<32; ++m ) {
				for(n=0; n<32; ++n ) {
					ms = mask32_32[m][n];
					idx = i-m;
					jdx = j-n;
					if( idx >= -1 && jdx >= -1 ) {
						index = idx + ( jdx * GRID_HEIGHT);
						rs += grid[index].r * ms;
						gs += grid[index].g * ms;
						bs += grid[index].b * ms;
					}
				}
			}			
			index = i + ( j * GRID_HEIGHT);			
			pf[index].r = rs;
			pf[index].g = gs;
			pf[index].b = bs;
		}
	}
	for( index=0; index<GRID_HEIGHT *GRID_WIDTH; index++ ) {
		grid[index].r = pf[index].r;
		grid[index].g = pf[index].g;
		grid[index].b = pf[index].b;
	}
	free( pf );
}
/************************
*						*
*						*
************************/
void smooth_8(  ) {
	double rs, gs, bs, ms;
	int i,j;
	register int index,m,n;
	int idx, jdx;


	float NOISE, theta;
	pic_format *pf = (pic_format *)malloc(GRID_WIDTH * GRID_HEIGHT * sizeof( pic_format ));
       if( ! pf ) {
	  printf("\nmalloc faliure in smooth_8. Exiting...\n");
	  free(grid);
	  exit(0);
       }
	
	printf("\nsmooth_8\n");

	for( i=0; i<GRID_HEIGHT; ++i ) {
		for(j=0; j<GRID_WIDTH; ++j ) {
			
			rs = gs = bs  = 0.0;
			for( m=0; m<8; ++m ) {
				for(n=0; n<8; ++n ) {
					ms = mask8_8[m][n];
					idx = i-m;
					jdx = j-n;
					if( idx >= -1 && jdx >= -1 ) {
						index = idx + ( jdx * GRID_HEIGHT);
						rs += grid[index].r * ms;
						gs += grid[index].g * ms;
						bs += grid[index].b * ms;
					}
				}
			}			
			index = i + ( j * GRID_HEIGHT);			
			pf[index].r = rs;
			pf[index].g = gs;
			pf[index].b = bs;
		}
	}
	for( index=0; index<GRID_HEIGHT *GRID_WIDTH; index++ ) {
		grid[index].r = pf[index].r;
		grid[index].g = pf[index].g;
		grid[index].b = pf[index].b;
	}
	free( pf );
}
/************************
*						*
*						*
************************/
void smooth_3() {
	double rs, gs, bs, ms;
	int i,j;
	register int index,m,n;
	int idx, jdx;


	float NOISE, theta;
	pic_format *pf = (pic_format *)malloc(GRID_WIDTH * GRID_HEIGHT * sizeof( pic_format ));
       if( ! pf ) {
	  printf("\nmalloc faliure in smooth_3. Exiting...\n");
	  free(grid);
	  exit(0);
       }
	
	printf("\nsmooth_3\n");

	for( i=0; i<GRID_HEIGHT; ++i ) {
		for(j=0; j<GRID_WIDTH; ++j ) {
			
			rs = gs = bs  = 0.0;
			for( m=0; m<3; ++m ) {
				for(n=0; n<3; ++n ) {
					ms = mask3_3[m][n];
					idx = i-m;
					jdx = j-n;
					if( idx >= -1 && jdx >= -1 ) {
						index = idx + ( jdx * GRID_HEIGHT);
						rs += grid[index].r * ms;
						gs += grid[index].g * ms;
						bs += grid[index].b * ms;
					}
				}
			}			
			index = i + ( j * GRID_HEIGHT);			
			pf[index].r = rs;
			pf[index].g = gs;
			pf[index].b = bs;
		}
	}
	for( index=0; index<GRID_HEIGHT *GRID_WIDTH; index++ ) {
		grid[index].r = pf[index].r;
		grid[index].g = pf[index].g;
		grid[index].b = pf[index].b;
	}
	free( pf );
}
/************************
*						*
*						*
************************/
void smooth_16() {
	double rs, gs, bs, ms;
	int i,j;
	register int index,m,n;
	int idx, jdx;


	float NOISE, theta;
	pic_format *pf = (pic_format *)malloc(GRID_WIDTH * GRID_HEIGHT * sizeof( pic_format ));
       if( ! pf ) {
	  printf("\nmalloc faliure in smooth_16. Exiting...\n");
	  free(grid);
	  exit(0);
       }
	
	printf("\nsmooth_16\n");

	for( i=0; i<GRID_HEIGHT; ++i ) {
		for(j=0; j<GRID_WIDTH; ++j ) {
			
			rs = gs = bs  = 0.0;
			for( m=0; m<16; ++m ) {
				for(n=0; n<16; ++n ) {
					ms = mask16_16[m][n];
					idx = i-m;
					jdx = j-n;
					if( idx >= -1 && jdx >= -1 ) {
						index = idx + ( jdx * GRID_HEIGHT);
						rs += grid[index].r * ms;
						gs += grid[index].g * ms;
						bs += grid[index].b * ms;
					}
				}
			}			
			index = i + ( j * GRID_HEIGHT);			
			pf[index].r = rs;
			pf[index].g = gs;
			pf[index].b = bs;
		}
	}
	for( index=0; index<GRID_HEIGHT *GRID_WIDTH; index++ ) {
		grid[index].r = pf[index].r;
		grid[index].g = pf[index].g;
		grid[index].b = pf[index].b;
	}
	free( pf );
}
/************************
*						*
*						*
************************/
void smooth_15() {
	double rs, gs, bs, ms;
	int i,j;
	register int index,m,n;
	int idx, jdx;


	float NOISE, theta;
	pic_format *pf = (pic_format *)malloc(GRID_WIDTH * GRID_HEIGHT * sizeof( pic_format ));
       if( ! pf ) {
	  printf("\nmalloc faliure in smooth_15. Exiting...\n");
	  free(grid);
	  exit(0);
       }
	
	printf("smooth_15\n");
   
	for( i=0; i<GRID_HEIGHT; ++i ) {
		for(j=0; j<GRID_WIDTH; ++j ) {
			
			rs = gs = bs  = 0.0;
			for( m=0; m<15; ++m ) {
				for(n=0; n<15; ++n ) {
					ms = mask15_15[m][n];
					idx = i-m;
					jdx = j-n;
					if( idx >= -1 && jdx >= -1 ) {
						index = idx + ( jdx * GRID_HEIGHT);
						rs += grid[index].r * ms;
						gs += grid[index].g * ms;
						bs += grid[index].b * ms;
					}
				}
			}			
			index = i + ( j * GRID_HEIGHT);			
			pf[index].r = rs;
			pf[index].g = gs;
			pf[index].b = bs;
		}
	}
	for( index=0; index<GRID_HEIGHT *GRID_WIDTH; index++ ) {
		grid[index].r = pf[index].r;
		grid[index].g = pf[index].g;
		grid[index].b = pf[index].b;
	}
	free( pf );
}

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
#define sgn(x) ((x<0)?-1:((x>0)?1:0)) /* macro to return the sign of a */
     
/************************
*						*
*						*
************************/
void plot_pixel( int la, int lb ) {
	register int index, b, a;
	
	
	for( a = la -1; a < la; a++ ) {
		for( b = lb -1; b < lb+3; b++ ) {
			index = a + ( GRID_WIDTH * b );
			grid[ index ].r = 11.0;
			grid[ index ].g = 11.0;
			grid[ index ].b = 11.0;
		}
	}
	
}
/**************************************************************************
 *  line_fast                                                             *
 *    draws a line using Bresenham's line-drawing algorithm, which uses   *
 *    no multiplication or division.                                      *
 **************************************************************************/

void line3d(int x1, int y1, int x2, int y2)
{
  int i,dx,dy,sdx,sdy,dxabs,dyabs,x,y,px,py;

  dx=x2-x1;      /* the horizontal distance of the line */
  dy=y2-y1;      /* the vertical distance of the line */
  dxabs=abs(dx);
  dyabs=abs(dy);
  sdx=sgn(dx);
  sdy=sgn(dy);
  x=dyabs>>1;
  y=dxabs>>1;
  px=x1;
  py=y1;

  //VGA[(py<<8)+(py<<6)+px]=color;
  plot_pixel(px,py);
  if (dxabs>=dyabs) /* the line is more horizontal than vertical */
  {
    for(i=0;i<dxabs;i++)
    {
      y+=dyabs;
      if (y>=dxabs)
      {
        y-=dxabs;
        py+=sdy;
      }
      px+=sdx;
      plot_pixel(px,py);
    }
  }
  else /* the line is more vertical than horizontal */
  {
    for(i=0;i<dyabs;i++)
    {
      x+=dxabs;
      if (x>=dyabs)
      {
        x-=dyabs;
        px+=sdx;
      }
      py+=sdy;
      plot_pixel(px,py);
    }
  }
  plot_pixel(px,py);
}
/************************
*						*
*						*
************************/
int in_list( plot_t a, plot_t list[], int n ) {
	int i;
	int rtv = 0;
	for( i = 0; i< n; i++ ) {
		if( a.v == list[i].v &&
		   a.x == list[i].x &&
		   a.y == list[i].y ) {
			rtv++;
		}
	}
	return rtv;
}
/************************
*						*
*						*
************************/
//int comp_plot( const plot_t *la, const plot_t *lb ) {
//	return ( la->v > lb->v ); 
//}

			
	
				
				
				
				
