/*
 *  copyright..:  (C)2007 Sebastian Mach
 *  contact....:  http://greenhybrid.net | seb@greenhybrid.net
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/****************************************************************************\

  What Monsieur Mach learned while trying to hack a 4k, Issue A
 ---------------------------------------------------------------
  (C)2007 Sebastian Mach
  http://greenhybrid.net | seb@greenhybrid.net

 * use constants which have dedicated support in the fpu (e.g. 0.0,1.0)
   can save 8 and more bytes per use
   e.g.: - imagine a function g() with return value [-1..+1]
         - you want to map it to [0..1]
         - instead of g()*0.5+0.5, you should definitely use (g()+1.0)*
           0.5
 * if a lot of calls to the same function exist, and if their return-
   val is not changed in code-structure,  then it may be better  to  do
   all the calls in a loop and save the results in an array  (see  e.g.
   defRandomXForms(), where a lot of calls to a random number generator
   have been pushed into a lookup-table generator)
 * changing lengths of arrays can cause size-explosions of >1k. do this
   carefully,  both  when  increasing and  decreasing. sizes of 2^n are
   less harsmfull in most cases.
 * SDL  eats  around  1k  for  simple  screen buffer alloc and surface-
   lockin g
 * SDL eats around 0.1k for SDL_WM_SetCaption()
 * test if loop unrolling is beneficial or not. a loop like
      "for(u=0; u<3; u++ ) c[u] = 0;"
   might be beneficial. a loop like
      "for(u=0; u<3; u++ ) c[u] = pow(x,4)/sqrt(y) * 3.14159;"
   not.
 * step by step: a) compile and check size; b) tweak; c) a);


 What Monsieur Mach learned while trying to hack a 4k, Issue B
 ---------------------------------------------------------------
  (C)2007 Sebastian Mach
  http://greenhybrid.net | seb@greenhybrid.net

 * why declare functions static? does that lower the size of functions?
   - no. but it says the compiler "heya,  that function will definitely
     only referenced to from within this file.   if not referenced from
	 within  this  file,  you  can  prune  it  and  save  space  in the
     binary".
 * if  you  want  to  know  the  current  state  of  key,   you can use
   SDL_PumpEvents and SDL_GetKeyState  instead  of  a  blown  SDL_Poll-
   Events-monstrum. that can save you several bytes  (but might not, if
   you need an event-polling anyway.
\****************************************************************************/


/****************************************************************************\
 * include                                                                  *
\****************************************************************************/
#include <SDL/SDL.h>
#include <dlfcn.h>
#include <math.h>



/****************************************************************************\
 * definitions                                                              *
\****************************************************************************/


#define IDIOT( C )  if( C ){ DUMPTEXT( "IDIOT!", 6 ); }

//>program args
#define WIDTH (640)
#define HEIGHT (480)

//>ifs args
#define SAMPLES_PER_CALL   64
#define DISCARD_SAMPLE_NUM 32
#define MAX_SAMPLE_LENGTH  512
#define MAX_NUM_XFORMS     10 /* adjust this with care! for some reason the size might go +1400 bytes */
#define MAX_NUM_XFORMS_SQ  (MAX_NUM_XFORMS*MAX_NUM_XFORMS)

//> below outcommented lines are for pure rotation, but see defRandomXForms
#define ROT_PROB              0.5
#define TRANS_AFTER_ROT_PROB  0.5
#define TRANS_AFTER_ROT_SCALE 0.5
#define ROT_SCALE             1.0
#define ROT_ADD               0.0


#define FLAME_RANDOM_COEFFICIENT   (FTMP2=sfrand(),FTMP2*FTMP2*FTMP2) /*pow(sfrand(),9)*/

#define RANDOM_NUM_XFORMS ( urand() % 5 + 4 )


//>program config
//#define DEFINE_FUNCTION_noise
//#define DEFINE_FUNCTION_operate
#define LINUX


//>low level
#ifdef LINUX
 #define DUMPTEXT( txt, len )                            \
 	asm volatile ( "":::"%eax", "%ebx", "%ecx", "%edx" );\
 	asm volatile ( "int $0x80"                           \
	:                                                    \
	: "a"(4), "b"(1), "c"(txt), "d"(len)                 \
	);                                                   \
	asm volatile ( "":::"%eax", "%ebx", "%ecx", "%edx" );

 #define BYEBYE() asm( "int $0x80" :: "a"(1), "b"(42) );
#endif



/****************************************************************************\
 * here go the types                                                        *
\****************************************************************************/
typedef double scalar;
typedef union _t_pixel{
	struct{
		scalar r,g,b,density;
	};
	scalar m[4];
} t_pixel;

/*typedef enum _t_OP{
	OP_ADD,
	OP_SUB,
	OP_MUL,
	OP_DIV
} t_OP;*/


#define NUM_FLAME_COEFFICIENTS  17
typedef union _t_flameCoeff{
	struct{
		scalar linear;
		scalar sinusoidal;
		scalar spherical;
		scalar swirl;
		scalar horseshoe;
		scalar polar;
		scalar handkerchief;
		scalar heart;
		scalar disc;
		scalar spiral;

		scalar hyperbolic;
		scalar diamond;
		scalar ex;
		scalar julia;
		scalar fisheye;
		scalar cosine;

		scalar cust_hyperbolic;
	};
	scalar coeff[NUM_FLAME_COEFFICIENTS];
} t_flameCoeff;

typedef union _t_xform{
	scalar m[9];
	struct{
		scalar x1, x2, x;
		scalar y1, y2, y;
		scalar r,g,b;
	};
} t_xform;


/*
typedef struct _t_dsmState{
	scalar registers[256];
	scalar stack[256];
	int stackPtr;
	unsigned int codePtr;
} t_dsmState;


typedef union _t_dsmOpCode{
	unsigned char opc  : 8; // op code
	unsigned char index : 8;
	char relAdr : 8;
} t_dsmOpCode;

enum DSM_OPCODE{
	DSM_MADD, DSM_INV, DSM_PUSH, DSM_POP, DSM_JG, DSM_DIE
};
*/



typedef SDL_Surface*(*SDL_SetVideoMode_t)(int, int, int, Uint32);
typedef int			(*SDL_Flip_t)(SDL_Surface*);
typedef int         (*SDL_LockSurface_t)  (SDL_Surface *surface);
typedef void        (*SDL_UnlockSurface_t)  (SDL_Surface *surface);
typedef Uint32      (*SDL_MapRGB_t)  (SDL_PixelFormat *fmt, Uint8 r, Uint8 g, Uint8 b);
typedef int         (*SDL_PollEvent_t)(SDL_Event *event);
typedef Uint8*      (*SDL_GetKeyState_t)(int *);
typedef void        (*SDL_PumpEvents_t)(void);
typedef void*       (*malloc_t)      (size_t);
typedef int (*rand_t)(void);
typedef void (*srand_t)(unsigned int seed);


/****************************************************************************\
 * here go the globals                                                      *
\****************************************************************************/
static t_pixel *g_fbuff;
static SDL_Surface *g_sdlbuff;

static unsigned int g_numXForms;
static t_xform *g_xforms;//[MAX_NUM_XFORMS+1]; //> "+1"=declare one more for use as temporary
static t_flameCoeff *g_flameCoeffs;//[MAX_NUM_XFORMS+1];//MAX_NUM_XFORMS+1];
static scalar *g_xformPBuffer;//[MAX_NUM_XFORMS+1];//> c above
#define FTMP  g_xformPBuffer[MAX_NUM_XFORMS]
#define FTMP2 g_xformPBuffer[MAX_NUM_XFORMS-1]

static scalar g_scaleX, g_scaleY;

static SDL_Flip_t sym_SDL_Flip;
static SDL_LockSurface_t   sym_SDL_LockSurface;
static SDL_UnlockSurface_t sym_SDL_UnlockSurface;
static SDL_MapRGB_t sym_SDL_MapRGB;

static rand_t sym_rand;
static srand_t sym_srand;


/****************************************************************************\
 * here go the function defs                                                *
\****************************************************************************/



/*--------------------------------------------------------------------------*\
 * grabbed from http://rgba.scenesp.org/articles/sfrand/sfrand.htm/thx dudes*
\*--------------------------------------------------------------------------*/
/*
static unsigned int mirand = 1;
static float sfrand( void )
{
    unsigned int a;

    mirand *= 16807;

    a = (mirand&0x007fffff) | 0x40000000;

    return( *((float*)&a) - 3.0f );
}*/

#define initrand( x )  sym_srand( x )
#define sfrand( ) (((float)sym_rand()/(0.5*(float)RAND_MAX))-1.0)
#define frand( ) (((float)sym_rand()/(float)RAND_MAX))
#define urand()   sym_rand()


/*--------------------------------------------------------------------------*\
 *                                                                          *
\*--------------------------------------------------------------------------*/
static inline void flushSurf( t_pixel *p_surf, int width, int height )
{
	register unsigned int xy;
	register unsigned int n = width*height;
	for( xy=0; xy<n; xy++ ){
		p_surf[ xy ].r =
		p_surf[ xy ].g =
		p_surf[ xy ].b =
		p_surf[ xy ].density = 0;
	}
}



/*--------------------------------------------------------------------------*\
 *                                                                          *
\*--------------------------------------------------------------------------*/
static inline void flipF2SDL( SDL_Surface *p_target, t_pixel *p_source, scalar scale, scalar densityScale )
{
	if( SDL_MUSTLOCK(p_target) && sym_SDL_LockSurface(p_target)<0 )
		return;
	register unsigned int x,y,u;
	for( y=0; y<p_target->h; y++ ){
		Uint32 *bufp   = (Uint32*)p_target->pixels + y*(p_target->pitch>>2);
		t_pixel *source = p_source + y*p_target->w;
		for( x=0; x<p_target->w; x++ ){
			unsigned char c[3];
			scalar D = 1+source->density*densityScale;
			scalar d = (255 * scale * ( log(D)/D ));
			//d = d * (0.7+0.3*cos(d*1.0));
			for( u=0; u<3; u++ ){
				scalar acc;
				acc = source->m[u]*d;
				acc = acc < 0   ? 0   :
				      acc > 255 ? 255 : acc;
				c[u] = (unsigned char)acc;
			}
			*(bufp++) = sym_SDL_MapRGB(p_target->format, c[0], c[1], c[2] );
			source++;
		}
	}


	if( SDL_MUSTLOCK(p_target) )
		sym_SDL_UnlockSurface(p_target);
	sym_SDL_Flip(p_target);
}




/*--------------------------------------------------------------------------*\
 * define random xforms for ifs                                             *
\*--------------------------------------------------------------------------*/
static inline void defRandomXForms( int xseed, int cseed )
{
	//> local vars
	unsigned int u,v;//,w;

	//> setup number of xforms scale
	initrand( xseed );
	g_numXForms = RANDOM_NUM_XFORMS;

	//float rbuff[15];
	t_xform *X = g_xforms;
	FTMP = 0;
	for( u=0; u<g_numXForms; X++, ++u ){

		/* define random flame coefficients */
		scalar flame = 0.0;
		for( v=0; v<NUM_FLAME_COEFFICIENTS; v++ ){
			g_flameCoeffs[u].coeff[v] = FLAME_RANDOM_COEFFICIENT;
			flame += g_flameCoeffs[u].coeff[v]*g_flameCoeffs[u].coeff[v];
		}

		flame = sqrt( flame );
		for( v=0; v<NUM_FLAME_COEFFICIENTS; v++ ){
			g_flameCoeffs[u].coeff[v] /= flame;
		}

		//> random xform + rgb
		for( v=0; v<6; v++ ){
			X->m[v] = frand()-0.5;
		}
		//> init prob of this xform...
		g_xformPBuffer[u] = frand();
		FTMP += g_xformPBuffer[u];

		/*
		//> init prob of this xform...

		//> define random flame coefficients
		scalar flame = 0.0;//frand();
		for( v=0; v<NUM_FLAME_COEFFICIENTS; v++ ){
			g_flameCoeffs[u].coeff[v] = FLAME_RANDOM_COEFFICIENT;
			flame += g_flameCoeffs[u].coeff[v]*g_flameCoeffs[u].coeff[v];
		}

		flame = 1./sqrt( flame );
		for( v=0; v<NUM_FLAME_COEFFICIENTS; v++ ){
			g_flameCoeffs[u].coeff[v] *= flame;
		}

		// define a random xform
		for( v=0; v<15; rbuff[v++]=frand() )
			;

		//> random xform + rgb
		for( v=0; v<6; v++ ){
			X->m[v] = rbuff[v]-0.5;
		}

		// doh, too many bytes, removed! then, removed the rbuff[] cruft too.
		if( rbuff[9]<ROT_PROB ){
			X->x = 0;
			X->y = 0;
			if( rbuff[10]<TRANS_AFTER_ROT_PROB ){
				X->x = TRANS_AFTER_ROT_SCALE*(rbuff[11]-0.5);
				X->y = TRANS_AFTER_ROT_SCALE*(rbuff[12]-0.5);
			}
			scalar a = ROT_ADD + ROT_SCALE * rbuff[13]*(2*3.141f);//2.*3.14159);
			X->y2 = -( X->x1 = sin(a));
			X->y1 =  ( X->x2 = cos(a));
		}


		//> init prob of this xform...
		g_xformPBuffer[u] = rbuff[14];
		FTMP += g_xformPBuffer[u];
		*/
	}
	//> normalize probs
	for( u=0; u<g_numXForms; u++ )
		g_xformPBuffer[u] /= FTMP;

	//> define random colors
	/* define a random xform */
	X = g_xforms;
	initrand( cseed );
	for( u=0; u<g_numXForms; ++X, ++u ){
		X->r = frand()+0.25;
		X->g = frand()+0.25;
		X->b = frand()+0.25;
	}

	//> setup output scale
	g_scaleX = 0.25;
	g_scaleY = 0.25;
}


/*--------------------------------------------------------------------------*\
 * burn it                                                                  *
\*--------------------------------------------------------------------------*/
static inline void flame( scalar *px, scalar *py, t_flameCoeff *p_coeff )
{
	static int num_flame_calls = 0;
	num_flame_calls++;
	const scalar pi = 3.14159;
	const scalar x = *px;
	const scalar y = *py;
	scalar nx = 0;
	scalar ny = 0;
	const scalar r2 = ( *px * *px + *py * *py );
	const scalar r  = sqrt( r2 );
	const scalar t  = atan( *py / *px );
	register scalar tr = t*r;
	register scalar julia_omega = ((num_flame_calls&0x1)==0)?0:pi;

	const scalar sin_r = sin(r);
	const scalar cos_r = cos(r);
	const scalar sin_t = sin(t);
	const scalar cos_t = cos(t);
	register scalar tmp;
	const scalar EPSILON = 0.00;


	/*static t_flameCoeff _coeff;
	p_coeff = &_coeff;

	//p_coeff->linear = 1.0;
	//p_coeff->ex = 1.0;
	//p_coeff->linear = 1.0;
	p_coeff->polar = 1.0;
	p_coeff->spherical = 2.5;
	p_coeff->julia  = 2.0;
	p_coeff->disc = 2.8;
	p_coeff->ex = 2;
	//p_coeff->cust_hyperbolic = 0.7;//*/

	// --- linear ---

	if( p_coeff->linear > EPSILON ){
		nx += p_coeff->linear * x;
		ny += p_coeff->linear * y;
	}
	// --- sinusoidal ---
	if( p_coeff->sinusoidal > EPSILON ){
		nx += p_coeff->sinusoidal * sin( x );
		ny += p_coeff->sinusoidal * sin( y );
	}

	// --- spherical ---
	if( p_coeff->spherical > EPSILON ){
		nx += p_coeff->spherical * x/r2;
		ny += p_coeff->spherical * y/r2;
	}

	// --- swirl ---
	if( p_coeff->swirl > EPSILON ){
		nx += p_coeff->swirl * r*cos(t+r);
		ny += p_coeff->swirl * r*sin(t+r);
	}

	// --- horseshoe ---
	if( p_coeff->horseshoe > EPSILON ){
		nx += p_coeff->horseshoe * r*cos(2*t);
		ny += p_coeff->horseshoe * r*sin(2*t);
	}

	// --- polar ---
	if( p_coeff->polar > EPSILON ){
		nx += p_coeff->polar * (t / pi);
		ny += p_coeff->polar * (r-1);
	}

	// --- handkerchief ---
	if( p_coeff->handkerchief > EPSILON ){
		nx += p_coeff->handkerchief * (r * sin(t+r));
		ny += p_coeff->handkerchief * (cos(t-r));
	}

	// --- heart ---
	if( p_coeff->heart > EPSILON ){
		nx += p_coeff->heart *  r * sin(tr);
		ny += p_coeff->heart * -r * cos(tr);
	}

	// --- disc ---
	if( p_coeff->disc > EPSILON ){
		nx += p_coeff->disc * ( ( t * sin(pi*r) ) / pi );
		ny += p_coeff->disc * ( ( t * cos(pi*r) ) / pi );
	}

	// --- spiral ---
	if( p_coeff->spiral > EPSILON ){
		nx += p_coeff->spiral * ( ( cos_t + sin_r ) / r );
		ny += p_coeff->spiral * ( ( sin_t - cos_r ) / r );
	}

	// --- hyperbolic ---
	if( p_coeff->hyperbolic > EPSILON ){
		nx += p_coeff->hyperbolic * ( sin_t/r );
		ny += p_coeff->hyperbolic * ( cos_t*r );
	}

	// --- diamond ---
	if( p_coeff->diamond > EPSILON ){
		nx += p_coeff->diamond * ( sin_t * cos_r );
		ny += p_coeff->diamond * ( cos_t * sin_r );
	}

	// --- ex ---
	if( p_coeff->ex > EPSILON ){
		tmp = sin(t+r);
		tmp *= tmp * tmp;
		nx += p_coeff->ex * ( r * tmp );
		tmp = cos(t-r);
		tmp *= tmp * tmp;
		ny += p_coeff->ex * ( r * tmp );
	}

	// --- julia ---
	if( p_coeff->julia > EPSILON ){
		nx += p_coeff->julia * ( sqrt(r) * cos( t/2 + julia_omega ) );
		ny += p_coeff->julia * ( sqrt(r) * sin( t/2 + julia_omega ) );
	}

	// --- fisheye ---
	if( p_coeff->fisheye > EPSILON ){
		nx += p_coeff->fisheye * ((2*r)/(r+1))*x;
		ny += p_coeff->fisheye * ((2*r)/(r+1))*y;
	}

	// --- cosine ---

	if( p_coeff->cosine > EPSILON ){
		// nx += p_coeff->cosine *  cos(pi*x)*cosh(y);
		// ny += p_coeff->cosine * -sin(pi*x)*sinh(y); //> not possible if we have no doubles
		nx += p_coeff->cosine *  cos(pi*x) * ( exp(y)+exp(-y) ) * 0.5;
		ny += p_coeff->cosine * -sin(pi*x) * ( exp(y)-exp(-y) ) * 0.5;
	}

	// --- cust_hyperbolic ---
	/*if( p_coeff->cust_hyperbolic > EPSILON ){
		nx += p_coeff->cust_hyperbolic * ( sin(t)/r );
		ny += p_coeff->cust_hyperbolic * ( cos(t)/r );
	}*/

	*px = nx;
	*py = ny;

}

/*--------------------------------------------------------------------------*\
 * samples the ifs                                                          *
\*--------------------------------------------------------------------------*/
static void moreSamples()
{
	register unsigned int sample,length, xi, sx, sy;
	scalar x,y, newx, newy;

	scalar c[3];

	for( sample=0; sample<SAMPLES_PER_CALL; sample++ ){
		x = sfrand(); //> x = [-1..+1]
		y = sfrand(); //> y = [-1..+1]*/
		c[0] = 0;
		c[1] = 0;//c[0];
		c[2] = 0;//c[1];
		for( length=0; length<MAX_SAMPLE_LENGTH; length++ ){

			/* select xform */
			newx = (sfrand()+1)*0.5;//> abusing newx
			for( xi=0; (newx-=g_xformPBuffer[xi])>0; xi++ );
			/* modify plotter color */
			newx = 0.2; // abusing newx
			newy = 1-newx; // abusing newy
			c[0] = newx*c[0] + newy*g_xforms[xi].r;
			c[1] = newx*c[1] + newy*g_xforms[xi].g;
			c[2] = newx*c[2] + newy*g_xforms[xi].b;
			/* multiply point with xform */
			newx = (g_xforms[xi].x1*x + g_xforms[xi].x2*y + g_xforms[xi].x);
			newy = (g_xforms[xi].y1*x + g_xforms[xi].y2*y + g_xforms[xi].y);
			flame( &newx, &newy, &g_flameCoeffs[xi] );
			x = newx;
			y = newy;
			/* scale to screen and plot */
			sx = (int)( (x*g_scaleX) * (scalar)WIDTH  ) + (WIDTH>>1);
			sy = (int)( (y*g_scaleY) * (scalar)HEIGHT ) + (HEIGHT>>1);
			if( length>DISCARD_SAMPLE_NUM
			    && sx >= 0 && sx < WIDTH
			    && sy >= 0 && sy < HEIGHT
			){
				t_pixel *pix = g_fbuff + sx+sy*WIDTH;
				pix->m[0] += c[0];
				pix->m[1] += c[1];
				pix->m[2] += c[2];
				pix->m[3] += 1.0;
			}
		}
	}
}

/*--------------------------------------------------------------------------*\
 * damn small itoa                                                          *
 * returns pascal like string (for use as ´DUMPTEXT( ret+1, *ret )´)        *
 * where DUMPTEXT( [ptrToString], [length] )                                *
\*--------------------------------------------------------------------------*/
static char *dsitoa( unsigned int num )
{
	static char str[16];
	char *tmp = str+15;
	int num_digits = 0;
	do{
		num_digits++;
		*tmp = num % 10 + '0';
		tmp--;
	}while( (num/=10)>0 );
	*tmp = num_digits;
	return tmp;
}



void _start()
{
	//> jeep vars
	unsigned int u;

	//> load libs
	void *libSDL = dlopen( "libSDL.so", RTLD_LAZY );
	void *libC = dlopen( "libc.so", RTLD_LAZY );
	#if 1
		SDL_SetVideoMode_t sym_SDL_SetVideoMode = dlsym(libSDL, "SDL_SetVideoMode");
		g_sdlbuff = sym_SDL_SetVideoMode(WIDTH,HEIGHT,32,SDL_HWSURFACE|SDL_DOUBLEBUF);
	#else
		((SDL_SetVideoMode_t)dlsym(libSDL, "SDL_SetVideoMode"))(WIDTH,HEIGHT,32,SDL_HWSURFACE|SDL_DOUBLEBUF);
	#endif


	//> need malloc, probably kinda craft (we only use it once :| )
	//> load some sdl cruft (cruft!)
	malloc_t sym_malloc = dlsym( libC, "malloc" );
	sym_rand   = dlsym( libC, "rand" );
	sym_srand  = dlsym( libC, "srand" );
	sym_SDL_Flip          = dlsym(libSDL, "SDL_Flip");
	sym_SDL_LockSurface   = dlsym(libSDL, "SDL_LockSurface");
	sym_SDL_UnlockSurface = dlsym(libSDL, "SDL_UnlockSurface");
	sym_SDL_MapRGB        = dlsym(libSDL, "SDL_MapRGB");
	Uint8 *keymap;
	{
		SDL_GetKeyState_t sym_SDL_GetKeyState = dlsym(libSDL, "SDL_GetKeyState");
		keymap = sym_SDL_GetKeyState(0);
	}
	SDL_PumpEvents_t sym_SDL_PumpEvents = dlsym( libSDL, "SDL_PumpEvents" );
	{
		int A = sizeof(t_pixel)*WIDTH*HEIGHT;
		int B = sizeof(t_xform) * (MAX_NUM_XFORMS+2);
		int C = sizeof(t_flameCoeff) * (MAX_NUM_XFORMS+2);
		int D = sizeof(scalar) * (MAX_NUM_XFORMS+2);
		void *teh_mem = sym_malloc( A+B+C+D );
		g_fbuff        = (t_pixel*)teh_mem;
		g_xforms       = (t_xform*)(teh_mem+=A);
		g_flameCoeffs  = (t_flameCoeff*)(teh_mem+=B);
		g_xformPBuffer = (scalar*)(teh_mem+C);
	}

	//> main loop goes here. it is pretty ugly
	unsigned int frameNum = 0;
	unsigned int xseed=666, cseed=222158903;
	redefine:{
		//xseed = frameNum>0 ? urand() : 666/*1714627440*/;
		//cseed = frameNum>0 ? urand() : 222158903/*1910190196*/;

		#if 0
			char *tmp;
			DUMPTEXT( "(", 1 );
			tmp = dsitoa( frameNum ); DUMPTEXT( tmp+1, *tmp ); DUMPTEXT( "): x", 4 );
			tmp = dsitoa( xseed ); DUMPTEXT( tmp+1, *tmp ); DUMPTEXT( ".c", 2 );
			tmp = dsitoa( cseed ); DUMPTEXT( tmp+1, *tmp ); DUMPTEXT( ".bmp\n", 5 );
		#endif

		u=0;
		defRandomXForms( xseed, cseed );
		flushSurf( g_fbuff, WIDTH, HEIGHT );
		frameNum++;
	}
	loop:{
		sym_SDL_PumpEvents();
		if( keymap[ SDLK_RETURN ] ){
			initrand( frameNum );
			xseed = urand();
			goto redefine; // {goto afterloop} >> when you want to save your art*/
		}
		if( keymap[ SDLK_BACKSPACE ] ){
			initrand( frameNum );
			cseed = urand();
			goto redefine; // {goto afterloop} >> when you want to save your art*/
		}
		if( keymap[ SDLK_ESCAPE ] )
			BYEBYE();//goto byebye;
		moreSamples();
		flipF2SDL( g_sdlbuff, g_fbuff, 1.0, 7  ); //> around 350 bytes
	}goto loop;

	/*afterloop:
		//SDL_SaveBMP( g_sdlbuff, "tmp.bmp" );
		goto redefine;*/
byebye:
		//atexit( SDL_QUIT );
		BYEBYE();
}