/* minor changes by Harald Deischinger:
   - un-fucked up Little Endian
   - use BUFF_WIDTH and BUFF_HEIGHT
   - filename as parameter
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <errno.h>
#include <time.h>

#ifdef BUFF_WIDTH
#define XSIZE BUFF_WIDTH
#else
#define XSIZE 320
#endif

#ifdef BUFF_HEIGHT
#define YSIZE BUFF_HEIGHT
#else
#define YSIZE 244
#endif

#define BSIZE (XSIZE*YSIZE)

#if (BSIZE > 65535)
typedef long tType;
#define MS SL
#else
typedef short tType;
#define MS SS
#endif

typedef int * trans_map;

typedef struct {				/* header for tab-files */
    long id;					/* "HDKB" to identify file */
    char description[40];			/* asciiz */
    short size_x;			
    short size_y;
} tab_header;

typedef struct {
	int x,y;
} ptType;

#ifdef MAC

// these are for reading fucked up Little Endian files from fucked up Little Endian machines
#define SS(s) (((s) & 0xff) << 8 | ((s) & 0xff00) >> 8)
#define SL(l) (((l) & 0xff) << 24 | ((l) & 0xff00) << 8 | ((l) & 0xff0000) >> 8 | ((l) & 0xff000000) >> 24)

#else

#define SS(s)  (s)
#define SL(l)  (l)
#endif

#ifndef PI
#define PI 3.14159265399
#endif

#define XP(d,l) ((d)*llen+(l))

main(int argc, char * argv[])
{
	int i,j,k,dx,dy,size,dist,q;
	ptType *nline;
	int *theTab,llen,cl,x,y,u,p,ox,oy,m,n,a,b;
	tType lineOut[XSIZE];
	FILE *f;
	tab_header theHeader;
	double ang,cx,cy,s,c,xf,yf,stepInc;
	
	srand(time(0));
	
	printf("Making random swirly file for %dx%d buffer...\n",XSIZE,YSIZE);
	
	// for scaling to the appropriate buffer size
	stepInc = (double)XSIZE / 2500; 
	
	theTab = malloc(sizeof(int)*BSIZE);
	if (!theTab) {
		printf("Not enough memory!\n");
		exit(1);
	}

	llen = (XSIZE<YSIZE ? XSIZE : YSIZE) * 0.35;
	cl = llen / 2;
	
	dist = 8/stepInc;
	
	nline = malloc(sizeof(ptType)*llen*dist);
	
	if (!nline) {
		printf("Not enough memory!\n");
		exit(1);
	}

	// init the line buffers
	for (j=0;j<dist;j++)
		for (k=0;k<llen;k++) {
			nline[XP(j,k)].x = 0;
			nline[XP(j,k)].y = k; 
		}
	
	// init the table
	for (j=0;j<YSIZE;j++)
		for (i=0;i<XSIZE;i++)
			theTab[i+j*XSIZE] = abs(i-3 + (j*XSIZE)) % BSIZE;
	
	cx = 0;
	cy = cl;
	ang = 0;
	p = rand() % 20;
	q = 0;
	a = 0;
	for (k=0;k<100000;k++) {
	
		// movement rate
//		if (rand() % 4) {
//			u = rand() % 3;
//			if (u == 0)
//				dist++;
//			else if (u == 1);
//				dist--;
//		}
				
		// angle rate of change
		if ((rand() % 50) == 1)
			p = (rand() % 20) - 10;
				
		ang += (float)p/360*stepInc;

		s = sin(ang)*stepInc;
		c = cos(ang)*stepInc;
		cx += s;
		cy += c;
	
		for (i=0;i<llen;i++) {
		
			x = nline[XP(a % dist,i)].x = (int)(cx + (cl-i)*c)%XSIZE;
			y = nline[XP(a % dist,i)].y = (int)(cy + (cl-i)*s)%YSIZE;
			
			ox = nline[XP((a+1) % dist,i)].x;
			oy = nline[XP((a+1) % dist,i)].y;
		
			dx = ox - x;
			dy = oy - y;
		
			theTab[abs(x+y*XSIZE)%BSIZE] = abs(x+dx + (y+dy)*XSIZE) % BSIZE;
			
			a++;
		}
		
		if (!(k % 100)) {
			printf(".");
			fflush(stdout);
		}
	}
	
	
	for (j=0;j<YSIZE;j++) {
	
		for (i=0;i<XSIZE;i++) {
		
			if (j==0 || j == YSIZE) {
			
				dx = (float)(cx - i) * 0.75;
				dy = cy - j;
				theTab[i+j*XSIZE] = abs(i+dx + ((j+dy)*XSIZE)) % BSIZE;
			
			} else {
	
				if (i==0 || i==XSIZE) {
					dx = cx - i;
					dy = (float)(cy - j) * 0.75;
					theTab[i+j*XSIZE] = abs(i+dx + ((j+dy)*XSIZE)) % BSIZE;
				}

			}
			
		}
	}
	
	
	printf("\nSaving...\n");
	
	theHeader.id = *((long*)"HDKB");
	strcpy(theHeader.description,"Krusty whirly 1");
	theHeader.size_x = SS(XSIZE);
	theHeader.size_y = SS(YSIZE);
		
	if (!(f = fopen( (argc>1)?argv[1]:"randswirls.tab","wb"))) {
		printf("Error opening randswirls.tab for writing binary\n%s\n",strerror(errno));
		exit(1);
	}
	
	fwrite( &theHeader, sizeof(tab_header), 1, f);
	
	for (j=0;j<YSIZE;j++) {
		
		for (i=0;i<XSIZE;i++)
			lineOut[i] = MS(theTab[i+j*XSIZE]);
	
		fwrite(lineOut,sizeof(tType)*XSIZE,1,f);
	}
	
	fclose(f);
	
	printf("Done.\n");
}




