#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

int Random(int range) {
    if ( range > 0)
	return rand() % range;
    else
	return 0;
}

#define BUFF_HEIGHT 480
#define BUFF_WIDTH 640

#define min(a, b)  (((a) < (b)) ? (a) : (b)) 
#define max(a, b)  (((a) > (b)) ? (a) : (b)) 

#define Y_CENTER  (BUFF_HEIGHT / 2)
#define X_CENTER  (BUFF_WIDTH / 2)

#define DEFAULT_SPEED 100
#define DEFAULT_RAND   70
#define DEFAULT_BLEND   8

int main (int argc, char **argv) {
    char   *fileName;
    FILE   *fp;
    long    x, y, dx, dy, map_x, map_y;
    long    speed, Randomness, Blend;
    bool   reverse;
	long lOffset, lFull, lBlend;

    if (argc < 2  ||  argc > 6) {
		char  *p = strrchr(argv[0], '\\');
		p = p ? p+1 : argv[0];
		printf ("\"Space flight\" table generator for Cthugha-4-Winamp.\n");
		printf ("The generated table creates an effect of flying forward through a\n");
		printf ("3-D space.\n");
		printf ("\n");
		printf ("Usage:  %s outfile.tab [speed] [Randomness] [Blend] ['r']\n", p);
		printf ("  Speed should be 30..300 (default %d)\n", DEFAULT_SPEED);
		printf ("  Randomness should be 0..100 (default %d)\n", DEFAULT_RAND);
		printf ("  Blend should be 0..255 (default %d)\n",DEFAULT_BLEND);
		printf ("  Adding a fifth argument will create a backward movement.\n");
		return 1;
    }

    fileName = argv[1];
    speed = (argc > 2) ? atoi(argv[2]) : DEFAULT_SPEED;
    Randomness = (argc > 3) ? atoi(argv[3]) : DEFAULT_RAND;
	Blend = (argc > 4) ? atoi(argv[4]) : DEFAULT_BLEND;
    reverse = (argc > 5);

    speed = min(max(speed,30),300);
    Randomness = min(max(Randomness,0),100);

    if ((fp = fopen(fileName, "wb")) == NULL) {
	printf ("*** Failed to create output file %s\n", fileName);
	return 2;
    }

    printf ("Generating table %s with %sspeed=%d and Randomness=%d\n",
	    fileName, reverse ? "reverse " : "", speed, Randomness);

    for (y = 0; y < BUFF_HEIGHT; y++) {
	printf ("Generating line %d of %d...\r", y + 1, BUFF_HEIGHT);

	for (x = 0; x < BUFF_WIDTH; x++) {
	    dx = x - X_CENTER;
	    dy = y - Y_CENTER;

	    if (! reverse  &&  abs(dx) < 30  &&  abs(dy) < 20  &&
	    Random(abs(dx)+abs(dy)) < 4) {

		map_x = Random(BUFF_WIDTH);
		map_y = Random(BUFF_HEIGHT);
	    } else {
		long  speedFactor;
		long sp;

		if (Randomness == 0)
		    sp = speed;
		else {
		    speedFactor = Random(Randomness + 1) - Randomness / 3;
		    sp = speed * (100L + speedFactor) / 100L;
		}

		if (reverse)
		    sp = (-sp);

		map_x = (long)(x - (dx * sp) / 700);
		map_y = (long)(y - (dy * sp) / 700);
	    }

	    if (map_y >= BUFF_HEIGHT || map_y < 0  ||
		map_x >= BUFF_WIDTH  || map_x < 0 ) {
		map_x = 0;
		map_y = 0;
	    }

		lOffset = map_y * BUFF_WIDTH + map_x;
		lBlend = Blend;
		lFull = lOffset + (lBlend << 24 );

	    if (fwrite (&lFull, sizeof(long), 1, fp) != 1) {
		printf ("\n*** Error while writing to output file (disk full?)\n");
		fclose (fp);
		return 3;
	    }
	}
    }

    printf ("Done.%26s\n", "");

    fclose (fp);

    return 0;
}
