///
/// file   : crparticles.tks
/// author : Bastian Spiegel <bastian.spiegel@web.de> <flink@tkscript.de>
/// descr. : TKS video test
/// license: provided "AS IS". no copyright, no liability. use as you want.
/// created: 040901
/// changed:
///          xx1101 <fli> added borders
///          120702 <fli> added "use callbacks"
///          300303 <fli> uses Debug.tks module now
///          090503 <fli> more compiled {} nodes
///

use "tksdl";

int num_psources=256;
int numparticles=256;
VectorArray va; va.alloc(num_psources); va.numElements=va.maxElements;
VectorArray vb; vb.alloc(num_psources); vb.numElements=vb.maxElements;
Texture pscmap2;
ParticleSystem ps;
Texture pscmap;
Texture pscmapa;
Texture ptexanim;
Texture ptexblurbuf;
Texture ptexblurdbuf;
int waitvsync=1;

function initParticles() {
    Texture tex_radfade;
    tex_radfade.loadImage("gfx/radfade.png", 32, 32, 4);
    Texture tex_fadebuf;

    if(!tex_fadebuf.alloc(32, 32, 4))
	die("out of memory");

    ps.allocParticles(numparticles);
    ps.resetParticles();
    
    pscmap2.loadImage("gfx/pscmap.png", 256, 1, 4);
    pscmap.loadImage("gfx/pscmapwhite.png", 256, 1, 4);
    pscmapa.loadImage("gfx/pscmapwhitea.png", 256, 1, 1);
    pscmap.interleaveAlpha(pscmapa);
    ps.setColormapModulation(pscmap);
    //ps.setParticleShader(PSSHA_SHIFTCMAP);
    /** create texture anim */
    ptexblurbuf.loadImage("gfx/flare-64x64.png", 32, 32, 4);

    if(!ptexblurdbuf.alloc(32, 32, 4))
	die("out of memory");
    if(!ptexanim.alloc(256, 256, 4))
	die("out of memory");

    int px;
    int py;
    IVector ivp=ivector(0,0), ivs=ivector(32,32), ivd;
    ptexblurdbuf.copyRegion(ptexblurbuf, ivp, ivs, ivp);
    for(py=0; py<8; py++)
	for(px=0; px<8; px++)
	    {
		ivd.init(px*32, py*32);
		tex_fadebuf.multiply(ptexblurdbuf, tex_radfade);
		ptexanim.copyRegion(tex_fadebuf, ivp, ivs, ivd);
    		ptexblurdbuf.simpleBlur(ptexblurbuf);
  		ptexblurbuf.copyRegion(ptexblurdbuf, ivp, ivs, ivp);
	    }
    ptexanim.colorKeyToAlpha(#00000000);
    ps.setTextureAnimation(ptexanim, 64, 32, 32);
    ps.setDefaultParticleSize2f(256.0, 256.0);
    
    tex_radfade.free();
    // -----------end init particles---------------
}


Texture tex;
WrappedFloat rot;
WrappedFloat rot2x;
WrappedFloat rot2y;
WrappedFloat rot2z;
WrappedFloat trot;
WrappedFloat psrot;

float vrotx=0.0;

function onDraw() compile {
    
	float dt=FPS.precision;
	
	vrotx+=0.02*dt;
	rot.tickPrecise(dt);
	rot2x.tickPrecise(dt);
	rot2y.tickPrecise(dt);
	rot2z.tickPrecise(dt);
	trot.tickPrecise(dt);
	ps.tickPrecise(dt);
	
	glClearColor(0.0,0.0,0.1,1);
	glClear(GL_COLOR_BUFFER_BIT);
	glColor4f(1,1,1,1);
  	zglInitPerspective(4.0/3.0, 60.0, 0.1, 128.0);
	glLoadIdentity();
    	glScalef((1.0/400.0), (1.0/300.0), (1.0/128.0));
    	glTranslatef(0.0, 0.0, -1024.0);
      	glMatrixMode(GL_PROJECTION);
      	glScalef(2.0, 1.0, 0.9);
	glRotatef(vrotx,0,0,1);
    	glMatrixMode(GL_MODELVIEW);
	glEnable(GL_TEXTURE_2D);
	glColor4f(0.5,0.5,0.5,1);

	Vector vc;
	Vector vs=vector(8, 8, 0);
	Vector vr;
	Vector vt;
	Vector pdv;
	Matrix m;
	int i;
	float f=0.0;
	ptexanim.bind();
	
	float fstep=PI2*(1.0/tcfloat(num_psources));
	Vector vi=vector(228.0, 128.0, 128.0);
	Matrix m2;
	float roti2x;
	float roti2y;
	float roti2z;
	roti2x=rot2x.value;
	roti2y=rot2y.value;
	roti2z=rot2z.value;
	Vector vpp;
	float fi=0.0;
	float fistep=0.020023001;
	float current_rot=rot.value;
	for(i=0; i<num_psources; i++)
	    {
		vr=vi;
		f+=fstep;
		fi+=fistep;
		m.init(0.0, 0.0, f+current_rot);
		vr.rotate(m);
		pdv=vr;
		vpp=pdv;
		pdv.unitScale(rnd(0.57)+0.653004);
		float pdvspd=pdv.getAbs()/2.23;
		Vector pdvr;
		pdvr.init(fi, roti2x, roti2z);
		pdv.rotate(pdvr);
		pdv.neg();
		vpp.unitScale(468.0);
		roti2x+=0.006009;
		roti2y+=0.0062501301;
		roti2z+=0.00041;
		m2.init(roti2x, roti2y, roti2z);
		vpp.rotate(m2);
		int c32=pscmap2.getXY32(rnd(255), 0);
		int a8=rnd(255);
		c32=(c32&$FFFFFF)|(a8<<24);
		ps.spawnParticle(vpp, tcint(600.0*pdvspd)+rnd(4)*128, c32, pdv);
	    }
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
	glDisable(GL_DEPTH_TEST);

	ps.draw();
	
	Debug.Draw();
	if(waitvsync) Viewport.waitVBlank();
}


function InitEmitters() compile {
    float f=0.0;
    int l=va.getNumElements();
    float fstep=PI2*(1.0/tcfloat(l));
    Vector vi=vector(128, 0, 10);
    Vector vc=vector(0, 0, 0);
    Vector vr;
    Matrix m;
    int i=0;
    loop(l)
	{
	    vr=vi;
	    f=f+fstep;
	    m.init(0, 0, f);
	    vr.rotate(m);
	    vr.add(vc);
	    va[i++]=vr;
	}
}

function onReopen {
    ptexanim.unload();
    ptexanim.upload();
    Debug.Init();
}

function SetNumParticles(int _num) {
    numparticles=_num;
    wrap numparticles 16 32768;
    ps.free();
    initParticles();
    trace ("numparticles set to "+numparticles);
}

function onKeyboard(Key _k) {
    if(_k.pressed) switch(_k.name) {
    case "v": waitvsync=1-waitvsync; trace "vsync set to "+waitvsync; break;
    case "up": SetNumParticles(numparticles+128);
    case "down": SetNumParticles(numparticles-128);
    default: Debug.OnKeyboard(_k); break;
    }
}

function main() {
    trace "crparticles starting..\n\n";
    trace "  space  : toggle screen clear mode (zini mode)";
    trace "  up     : increase number of particles +16";
    trace "  down   : decrease number of particles -16";
    trace "  d      : toggle debug overlay";
    trace "  ctrl-d : toggle console debug output";
    trace "  f      : switch to fullscreen mode";
    trace "  g      : (un-)grab mouse";

    trace "enterevents";

    Viewport.setScreenResolution(512,384,32);
    Viewport.openWindow(320, 200);
    FPS.tickInterval=2;
    FPS.tickBuffer=20;
    
    initParticles();
    ptexanim.setFlags(TEX_MODULATE);
    onReopen();
    InitEmitters();
    
    rot.init(0, 0.01, 0, 2PI);
    rot2x.init(0, 0.0021228, 0, 2PI);
    rot2y.init(0, 0.0036365, 0, 2PI);
    rot2z.init(0, 0.00135, 0, 2PI);
    trot.init(0, 0.001, 0, 2PI);
    psrot.init(0, 0.00111, 0, 2PI);
    
    use callbacks;
    SDL.eventLoop();
}