#ifdef _DEBUG
	#include <stdlib.h>
	#include "../mmgr.h"
#endif

#include <math.h>

#include "myrsky.hpp"
#include "../mathematics.hpp"
#include "../primitives.hpp"

#define PARTICLE_COUNT 1000

void lookAt_()
{
/*
	gluLookAt(  4.50f, 0.729724f, 4.9f,
				0,0,0,
				0,1,0);
*/
	cam->useCamera(2);
}


void Myrsky::RenderReflection(float pos, float alpha)
{
	glExt.bindTextureFBO512(glExt.glowTexture512ID);

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glLoadIdentity();
		lookAt_();

		glPushMatrix();
		glTranslatef(0.0f, 0.0f, 0.0f);
		glScalef(1.0, -1.0, 1.0);
		double plane[4] = {0.0, 1.0, 0.0, 0.0}; //water at y=0
		glEnable(GL_CLIP_PLANE0);
		glClipPlane(GL_CLIP_PLANE0, plane);
			drawScene(pos, alpha);
		glDisable(GL_CLIP_PLANE0);
		glPopMatrix();

	glExt.unbindFBO();
}

void Myrsky::RenderRefractionAndDepth(float pos, float alpha)
{
    glExt.bindDepthFBO();

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glLoadIdentity();
		lookAt_();

		glPushMatrix();
		glTranslatef(0.0f, 0.0f, 0.0f);
		//normal pointing along negative y
		double plane[4] = {0.0, -1.0, 0.0, 0.0};
		glEnable(GL_CLIP_PLANE0);
		glClipPlane(GL_CLIP_PLANE0, plane);
			drawScene(pos, alpha);
		glDisable(GL_CLIP_PLANE0);
		glPopMatrix();

	glExt.unbindFBO();
}

void Myrsky::RenderWater(float pos, float alpha)
{

	shaders.waterReflect2->bind();

	shaders.waterReflect2->setUniform1f("fade",  alpha*alpha*alpha);	// time!

	shaders.waterReflect2->setUniform1f("time",  13.0f*pos);	// time!
	shaders.waterReflect2->setUniform1f("time2", 25.0f*pos);
	
	shaders.waterReflect2->setUniform4f("viewpos", 100, 100, 100,1);
	//shaders.waterReflect2->setUniform4f("lightpos", -3.5, 10, 3.5, 1);
	shaders.waterReflect2->setUniform4f("lightpos", -1330.5, 1400, 1230.5, 1);

	shaders.waterReflect2->setUniform4f("waterColor", 0.1473f*alpha, 0.2163f*alpha, 0.37406f*alpha, 1.0f*alpha);

	glColor3f(1,1,1);

    glActiveTextureARB(GL_TEXTURE0_ARB);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, glExt.glowTexture512ID);
	shaders.waterReflect2->setUniform1i("water_reflection", 0);

    glActiveTextureARB(GL_TEXTURE1_ARB);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, glExt.depthColTex); //refraction
	shaders.waterReflect2->setUniform1i("water_refraction", 1);

    glActiveTextureARB(GL_TEXTURE2_ARB);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, dmsGetTexture("water_normalmap.jpg")->getID());
	shaders.waterReflect2->setUniform1i("water_normalmap", 2);

    glActiveTextureARB(GL_TEXTURE3_ARB);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, dmsGetTexture("water_distort.jpg")->getID());
	shaders.waterReflect2->setUniform1i("water_dudvmap", 3);

    glActiveTextureARB(GL_TEXTURE4_ARB);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, glExt.depthTex);
	shaders.waterReflect2->setUniform1i("water_depthmap", 4);

    glActiveTextureARB(GL_TEXTURE5_ARB);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, dmsGetTexture("envmap.jpg")->getID());
	shaders.waterReflect->setUniform1i("water_envmap", 5);

    glBegin(GL_QUADS);
    glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0f, 5.0f);
    glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0f, 20.0f);
    glMultiTexCoord2fARB(GL_TEXTURE2_ARB, 0.0f, 20.0f);
    glMultiTexCoord2fARB(GL_TEXTURE3_ARB, 0.0f, 20.0f);
    glMultiTexCoord2fARB(GL_TEXTURE4_ARB, 0.0f, 20.0f);
	glMultiTexCoord2fARB(GL_TEXTURE5_ARB, 0.0f, 1.0f);
    glVertex3f(-150.0f, 0.0f, 150.0f);
    glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0f, 0.0f);
    glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0f, 0.0f);
    glMultiTexCoord2fARB(GL_TEXTURE2_ARB, 0.0f, 0.0f);
    glMultiTexCoord2fARB(GL_TEXTURE3_ARB, 0.0f, 0.0f);
    glMultiTexCoord2fARB(GL_TEXTURE4_ARB, 0.0f, 0.0f);
	glMultiTexCoord2fARB(GL_TEXTURE5_ARB, 0.0f, 0.0f);
    glVertex3f(-150.0f, 0.0f, -150.0f);
    glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 5.0f, 0.0f);
    glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 20.0f, 0.0f);
    glMultiTexCoord2fARB(GL_TEXTURE2_ARB, 20.0f, 0.0f);
    glMultiTexCoord2fARB(GL_TEXTURE3_ARB, 20.0f, 0.0f);
    glMultiTexCoord2fARB(GL_TEXTURE4_ARB, 20.0f, 0.0f);
	glMultiTexCoord2fARB(GL_TEXTURE5_ARB, 1.0f, 0.0f);
    glVertex3f(50.0f, 0.0f, -150.0f);
    glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 5.0f, 5.0f);
    glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 20.0f, 20.0f);
    glMultiTexCoord2fARB(GL_TEXTURE2_ARB, 20.0f, 20.0f);
    glMultiTexCoord2fARB(GL_TEXTURE3_ARB, 20.0f, 20.0f);
    glMultiTexCoord2fARB(GL_TEXTURE4_ARB, 20.0f, 20.0f);
	glMultiTexCoord2fARB(GL_TEXTURE5_ARB, 1.0f, 1.0f);
    glVertex3f(150.0f, 0.0f, 150.0f);
    glEnd();

    glActiveTextureARB(GL_TEXTURE0_ARB);
    glDisable(GL_TEXTURE_2D);

    glActiveTextureARB(GL_TEXTURE1_ARB);
	glDisable(GL_TEXTURE_2D);

    glActiveTextureARB(GL_TEXTURE2_ARB);
	glDisable(GL_TEXTURE_2D);

    glActiveTextureARB(GL_TEXTURE3_ARB);
	glDisable(GL_TEXTURE_2D);

    glActiveTextureARB(GL_TEXTURE4_ARB);
    glDisable(GL_TEXTURE_2D);

    glActiveTextureARB(GL_TEXTURE5_ARB);
    glDisable(GL_TEXTURE_2D);

	glActiveTextureARB(GL_TEXTURE0_ARB);

	shaders.unbind();

}

void MyrskyTaika::draw(float pos, float alpha)
{
    float t = Mathematics::calcPosFloat(pos, this->st, this->et);//Mathematics::calcSaturate(pos, this->st, this->et, 5);

    float advance = 1+sinf(powf(pos, 23)*3.141592f*0.5f)*5;

    if (t > 0.0001f && t < 0.999999f)
    {
        float a = fmodf(this->speed*pos + this->phase, 1)*2*3.141592f;

        glColor4f(this->color.x, this->color.y, this->color.z, alpha*Mathematics::calcSaturate(t, 0, 1, 4));
		glEnable(GL_LINE_SMOOTH);
        glBegin(GL_LINE_STRIP);

        for (float u = a; u < a + this->width; u += 0.1f)
        {
            float r = this->radius*advance + u*0.2f;
            Vector v = Vector(cosf(u)*r, this->y*t, sinf(u)*r);
            glVertex3fv((float *)&v);

        }
        glEnd();
		glDisable(GL_LINE_SMOOTH);



    }
}



// lifetime of particle
const float maxlifetime = 5500;

void Myrsky::draw()
{
	const float pos = (time - startTime) / (endTime - startTime);
	float alpha = 1.0f;

	const float fadeinstart = 0.0f;
	const float fadeinstop = 0.1f;
	const float fadeoutstart = 0.90f;
	const float fadeoutstop = 1.0f;

	if (pos >= fadeinstart && pos <= fadeinstop)
		alpha *= (pos-fadeinstart) / (fadeinstop-fadeinstart);
	if (pos >= fadeoutstart && pos <= fadeoutstop)
		alpha *= 1-(pos-fadeoutstart) / (fadeoutstop-fadeoutstart);

	renderScene(pos, alpha);
}

Vector Myrsky::turbulenceFunc1(float t,Vector &pos)
{
    const float m = 1.8f;

    const float x = 0.7f*cosf(pos.x*m*t*12)+1.1f*sinf(pos.y*m*t*8)+0.52f*cosf(pos.z*m*t*17); 
    const float y = 0.9f*cosf(pos.x*m*t*19)+1.6f*sinf((pos.y-0.6f*pos.x)*m*t*18)+1.22f*cosf(pos.z*m*t*6); 
    const float z = 1.4f*cosf(pos.x*m*t*9)+0.98f*sinf(pos.y*m*t*12)+1.42f*cosf((pos.z-0.6f*pos.x)*m*t*6); 

    return Vector(x, y, z);

}
Vector Myrsky::turbulenceFunc2(float t,Vector &pos)
{
    const float m = 2.4f;

    const float x = 1.9f*cosf(pos.x*m*t*11)+1.1f*sinf(pos.y*m*t*9)+0.32f*cosf(pos.z*m*t*11); 
    const float y = 1.3f*cosf(pos.x*m*t*5)+1.6f*sinf((pos.y-0.9f*pos.x)*m*t*18)+0.82f*cosf(pos.z*m*t*8); 
    const float z = 0.3f*cosf(pos.x*m*t*32)+0.38f*sinf(pos.y*m*t*13)+0.82f*cosf((pos.z-0.6f*pos.x)*m*t*15); 

    return Vector(x, y, z);

}
Vector Myrsky::turbulenceFunc3(float t,Vector &pos)
{
    const float m = 1.3f;

    const float x = 1.5f*cosf(pos.x*m*t*13)+1.1f*sinf(pos.y*m*t*5)+0.52f*cosf(pos.z*m*t*21); 
    const float y = 1.1f*cosf(pos.x*m*t*15)+1.6f*sinf((pos.y-0.151f*pos.x)*m*t*19)+1.22f*cosf(pos.z*m*t*11); 
    const float z = 0.6f*cosf(pos.x*m*t*16)+0.98f*sinf(pos.y*m*t*9)+1.42f*cosf((pos.z-0.4f*pos.x)*m*t*9); 

    return Vector(x, y, z);

}

void Myrsky::updateParticles(float pos)
{
    static int prevtime = 0;
    static int particlecumultime = 0;
    static int particleindex = 0;





    int currenttime = dmsGetModulePosition();
    int dt = currenttime - prevtime;
    prevtime = currenttime;

    if (dt < 0)
        dt = -dt; 

    particlecumultime += dt;
    const int maxcycles = 20;

    const int particleupdatelimit = 1000/300; //100 fps = 2-3 krt/frame
    if (particlecumultime > maxcycles*particleupdatelimit)
        particlecumultime = maxcycles*particleupdatelimit;

    float puhallus = powf(Mathematics::calcPosFloat(pos, 0.92f, 1.00f), 2.5f);

	// opt.
	const float PI_2 = 2*3.141592f;

    //kuinka monta lehteä on olemassa

    const int particlecount = (int)(maxparticles / 4 + (maxparticles * 3 / 3) * Mathematics::calcPosFloat(pos, 0.0f, 0.5f));
    static int particlenum = 0;

    while ((particlecumultime > particleupdatelimit))
    {
        //lisätään particlet

        if (currenttime < (int)(endTime - 2500))
        {
            for (int i = 0; i < 5; i++)
            {
                if (!particles[particleindex].active && particlenum < particlecount)
                {
                    particles[particleindex].active = true;

                    float a = Mathematics::randFloat()*PI_2;
                    //float r = powf(Mathematics::randFloat(), 0.7f)*17;
					float r = Mathematics::randFloat()*17;

                    Vector position = Vector(cosf(a)*r, Mathematics::randBetween(1, 5), sinf(a)*r);
                    particles[particleindex].pos = position;
                    particles[particleindex].startrotation = Mathematics::randVectSphere()*PI_2;

                    particles[particleindex].endrotation = particles[particleindex].startrotation + 
                        Mathematics::randVectSphere()*(1.5f+Mathematics::randFloat()*1.4f)*3.141592f;

                    float e = Mathematics::randBetween(0.3f, 0.7f);
                    particles[particleindex].energy = e;
                    particles[particleindex].maxenergy = e;
                    particles[particleindex].size = Mathematics::randBetween(0.165f, 0.29f);

                    const float raja = 0.5f;

                    if (Mathematics::randFloat() < (pos-raja)/raja)
                    {
                        particles[particleindex].special = true;
                    }
                    else
                    {
                        particles[particleindex].special = false;
                    }
                    particlenum++;
            
                }
                particleindex++;
                particleindex %= maxparticles;
            }
        }

        Vector valo = Vector(3, 1, -4).normalize();
        //päivitetään particleja
        Matrix turbrot;

        Matrix totalrot;
        totalrot.makeRotation(0, pos*3 + powf(pos, 2)*12, 0);

        Matrix singlerot;
        singlerot.makeIdentity();

	// opt.
	const float END_TURB = pos*0.009f;

        for (int j = 0; j < maxparticles; j++)
        {
            if (particles[j].active)
            {
                particles[j].energy -= 0.0005f;
                if (particles[j].energy < 0.0f || particles[j].pos.y < 0)
                {
                    particles[j].active = false;
                    particlenum--;
                }
                else
                {
                    float t = particles[j].energy / particles[j].maxenergy;
                    const float r = 0.2f;//7f;

                    const float turbulence = 0.002f + END_TURB;
/*
                    turbrot.makeRotation(particles[j].pos.x*r+pos*11, particles[j].pos.y*r+pos*5,-particles[j].pos.z*r+pos*17);
                    switch(j%3)
                    {
                        case 0: particles[j].pos += (turbulenceFunc1(pos, particles[j].pos)*turbrot)*turbulence; break;
                        case 1: particles[j].pos += (turbulenceFunc2(pos, particles[j].pos)*turbrot)*turbulence; break;
                        case 2: particles[j].pos += (turbulenceFunc3(pos, particles[j].pos)*turbrot)*turbulence; break;
                    }
*/
                    switch(j%3)
                    {
                        case 0: particles[j].pos += (turbulenceFunc1(pos, particles[j].pos))*turbulence; break;
                        case 1: particles[j].pos += (turbulenceFunc2(pos, particles[j].pos))*turbulence; break;
                        case 2: particles[j].pos += (turbulenceFunc3(pos, particles[j].pos))*turbulence; break;
                    }
                    //liike
                    particles[j].pos.x += 0.004f;

                    float radius = particles[j].pos.length();


                    if ((j % 2) == 0)
                    {
                        const float maxradius = 25.0f;
                        singlerot.makeRotation(0, powf(pos, 1.4f)*21*powf((maxradius - radius) / maxradius, 2.4f), 0);
                    }

                    float s = particles[j].size * Mathematics::calcSaturate(t, 0, 1, 3);
                    Vector ro = particles[j].startrotation*(1-t) + particles[j].endrotation*t;
                    Matrix rot;
                    rot.makeRotation(ro.x, ro.y, ro.z);

                    particles[j].l = 0.1f+0.9f*fabsf(valo.dotProduct(ro.normalize()));

                    Vector p = (particles[j].pos * singlerot) * totalrot;

                    p *= 1 + puhallus*7;
                    particles[j].v1 = p + Vector(-s, -s, 0)*rot;
                    particles[j].v2 = p + Vector( s, -s, 0)*rot;
                    particles[j].v3 = p + Vector( s,  s, 0)*rot;
                    particles[j].v4 = p + Vector(-s,  s, 0)*rot;

                    particles[j].pos2 = p;
                }
            }
        }
        particlecumultime -= particleupdatelimit;
    }

}

void Myrsky::renderSky(float pos, float sync, float alpha)
{


	//glCullFace(GL_BACK);
	//glEnable(GL_CULL_FACE);

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_DEPTH_TEST);

	int i;
	
	glEnable(GL_TEXTURE_2D);

	//////////////////
	// isoin katto
	//////////////////

	T3D *object1 = dmsGetObject("sp.t3d");
	int objectvertexcount = object1->getVertexCount();
	int objectfacecount = object1->getFaceCount();
	T3DFace *objectfaces = object1->getFaceArray();
	T3DVertex *objectvertices = object1->getVertexArray();

	//////////////////
	// taivas/pilvet
	//////////////////
/*
	Vector clearcol = Vector(0.3f, 0.4f,0.4f);
	glClearColor(clearcol.x,clearcol.y,clearcol.z,0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
*/
	const float add = sync*0.25f;

	glPushMatrix();
	


		glColor4f((add+0.6f)*alpha,(add+0.6f)*alpha,(add+0.6f)*alpha,(0.52795f+add)*alpha);
		//glColor4f(1,1,1, 0.65f*alpha);
		glScalef(11, 6.25f, 11);
		//glRotatef(175.0f+pos*-55,0.1f,0.2f,1); 
		glRotatef(180, 0, 0, 1);
		glRotatef(175.0f+pos*-55, 0,1,0); 
		
		glBindTexture(GL_TEXTURE_2D, dmsGetTexture("sky4.jpg")->getID());
		
		glBegin(GL_TRIANGLES);
		for (i=0;i<objectfacecount;i++)
		{
			//glNormal3fv((float *)&objectfaces[i].normal);
			glTexCoord2f(objectvertices[objectfaces[i].a].u, objectvertices[objectfaces[i].a].v);
			 glVertex3fv((float *)&objectvertices[objectfaces[i].a].position);
			//glNormal3fv((float *)&objectfaces[i].normal);
			glTexCoord2f(objectvertices[objectfaces[i].b].u, objectvertices[objectfaces[i].b].v);
			 glVertex3fv((float *)&objectvertices[objectfaces[i].b].position);
			//glNormal3fv((float *)&objectfaces[i].normal);
			glTexCoord2f(objectvertices[objectfaces[i].c].u, objectvertices[objectfaces[i].c].v);
			 glVertex3fv((float *)&objectvertices[objectfaces[i].c].position);
		}
		glEnd();

	glPopMatrix();

	glPushMatrix();
	
	    //glColor4f(1,1,1, 0.305f*alpha);
		glColor4f((0.8f+sync*0.1f)*alpha,(0.89f+sync*0.1f)*alpha,1*alpha, (sync*0.3f+0.4621305f)*alpha);

	    glScalef(10, 5.5f, 10);
	    glRotatef(180, 0, 0, 1);
		
		glBindTexture(GL_TEXTURE_2D, dmsGetTexture("hmap.jpg")->getID());
		glBegin(GL_TRIANGLES);
		for (i=0;i<objectfacecount;i++)
		{
			//glNormal3fv((float *)&objectfaces[i].normal);
			glTexCoord2f(objectvertices[objectfaces[i].a].u, objectvertices[objectfaces[i].a].v);
			 glVertex3fv((float *)&objectvertices[objectfaces[i].a].position);
			//glNormal3fv((float *)&objectfaces[i].normal);
			glTexCoord2f(objectvertices[objectfaces[i].b].u, objectvertices[objectfaces[i].b].v);
			 glVertex3fv((float *)&objectvertices[objectfaces[i].b].position);
			//glNormal3fv((float *)&objectfaces[i].normal);
			glTexCoord2f(objectvertices[objectfaces[i].c].u, objectvertices[objectfaces[i].c].v);
			 glVertex3fv((float *)&objectvertices[objectfaces[i].c].position);
		}
		glEnd();

	glPopMatrix();

	//glDisable(GL_CULL_FACE);
}
void Myrsky::drawScene(float pos, float alpha)
{
    int i;

	float sync = trigger->get(dmsGetModulePosition());

    if (pos > 0.5f)
    {
        renderSky(pos, sync, 1);
    }
    else
    {
        renderSky(pos, sync, alpha);
    }

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
	glDisable(GL_DEPTH_TEST);
    glDisable(GL_TEXTURE_2D);
    glLineWidth(3.0f);

    for (i = 0; i < taikacount; i++)
    {
        taiat[i]->draw(pos, alpha);
    }

	////////////////
	// partikkelit
	////////////////

    Vector light = Vector(3,1,-4).normalize();
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	Vector x=Vector(), y=Vector(), z=Vector();
	Mathematics::antiRotate(&x, &y, &z);


    float lalpha = 1.0f;

	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("leaf_01.png")->getID());
    glBegin(GL_QUADS);
    for (i = 0; i < maxparticles / 4; i++)
    {
        if (particles[i].active)
        {
            {
                glColor4f(particles[i].l, particles[i].l, particles[i].l, lalpha);
            }
            glTexCoord2f(0, 0);
            glVertex3fv((float *)&particles[i].v1);
            glTexCoord2f(1, 0);
            glVertex3fv((float *)&particles[i].v2);
            glTexCoord2f(1, 1);
            glVertex3fv((float *)&particles[i].v3);
            glTexCoord2f(0, 1);
            glVertex3fv((float *)&particles[i].v4);
        }
    }

    glEnd();

    
    
    
	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("leaf_02.png")->getID());
    glBegin(GL_QUADS);
    for (i = maxparticles / 4; i < maxparticles / 2; i++)
    {
        if (particles[i].active)
        {
            {
                glColor4f(particles[i].l, particles[i].l, particles[i].l, lalpha);
            }
            glTexCoord2f(0, 0);
            glVertex3fv((float *)&particles[i].v1);
            glTexCoord2f(1, 0);
            glVertex3fv((float *)&particles[i].v2);
            glTexCoord2f(1, 1);
            glVertex3fv((float *)&particles[i].v3);
            glTexCoord2f(0, 1);
            glVertex3fv((float *)&particles[i].v4);
        }
    }

    glEnd();
    
    
    
 	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("leaf_03.png")->getID());
    glBegin(GL_QUADS);
    for (i = maxparticles / 2; i < maxparticles * 3 / 4; i++)
    {
        if (particles[i].active)
        {
            {
                glColor4f(particles[i].l, particles[i].l, particles[i].l, lalpha);
            }
            glTexCoord2f(0, 0);
            glVertex3fv((float *)&particles[i].v1);
            glTexCoord2f(1, 0);
            glVertex3fv((float *)&particles[i].v2);
            glTexCoord2f(1, 1);
            glVertex3fv((float *)&particles[i].v3);
            glTexCoord2f(0, 1);
            glVertex3fv((float *)&particles[i].v4);
        }
    }

    glEnd();
   
    
    
    
    
    
    
	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("leaf_04.png")->getID());
    glBegin(GL_QUADS);
    for (i = maxparticles * 3 / 4; i < maxparticles ; i++)
    {
        if (particles[i].active)
        {
            {
                glColor4f(particles[i].l, particles[i].l, particles[i].l, lalpha);
            }
            glTexCoord2f(0, 0);
            glVertex3fv((float *)&particles[i].v1);
            glTexCoord2f(1, 0);
            glVertex3fv((float *)&particles[i].v2);
            glTexCoord2f(1, 1);
            glVertex3fv((float *)&particles[i].v3);
            glTexCoord2f(0, 1);
            glVertex3fv((float *)&particles[i].v4);
        }
    }

    glEnd();
    
    
    
    
    
    
    
    
    
    /*
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
	glDisable(GL_DEPTH_TEST);
	glBindTexture(GL_TEXTURE_2D, dmsGetTexture("purpleparticle.jpg")->getID());
    glBegin(GL_QUADS);
    glColor4f(1,1,1, alpha*1.2f);

    const float size = 0.4f;
	Vector v1 = x*-size - y*size;
	Vector v2 = x*size  - y*size;
	Vector v3 = x*size  + y*size;
	Vector v4 = x*-size + y*size;
    

    for (i = 0; i < maxparticles; i++)
    {
        if (particles[i].special)
        {
            glTexCoord2f(0, 0);
            glVertex3fv((float *)&(particles[i].pos2 + v1));
            glTexCoord2f(1, 0);
            glVertex3fv((float *)&(particles[i].pos2 + v2));
            glTexCoord2f(1, 1);
            glVertex3fv((float *)&(particles[i].pos2 + v3));
            glTexCoord2f(0, 1);
            glVertex3fv((float *)&(particles[i].pos2 + v4));
        }
    }

    glEnd();
*/



/**/
/*
	Vector light = Vector(3,1,-4).normalize();
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	Vector x=Vector(), y=Vector(), z=Vector();
	Mathematics::antiRotate(&x, &y, &z);


	// poispäin liike
	Vector speed = Vector(0.75f,0,0.01f);

	int n=0;

	MyrskyP *p = NULL;
	list->goToStart();
	do {	
		p = (MyrskyP *)(list->getCurrent());
		if(p!=NULL) 
		{
			
			const int NUM = PARTICLE_COUNT/4;
			
			if(n==0)
				glBindTexture(GL_TEXTURE_2D, dmsGetTexture("leaf_01.png")->getID());
			else if(n==NUM)
				glBindTexture(GL_TEXTURE_2D, dmsGetTexture("leaf_02.png")->getID());
			else if(n==NUM*2)
				glBindTexture(GL_TEXTURE_2D, dmsGetTexture("leaf_03.png")->getID());
			else if(n==NUM*3)
				glBindTexture(GL_TEXTURE_2D, dmsGetTexture("leaf_04.png")->getID());
			p->pos += speed*dmsGetDeltaTime();


			n++;
			

			Vector drawpos = p->pos;
			drawpos.x += sinf(p->size*dmsGetDeltaTime()*0.1f)*16.0f;
			drawpos.y += cosf(p->size*dmsGetDeltaTime()*0.31f)*16.0f;

			// väri lerpataan drawposista
			// Vector color = Vector(0.45f,0.45f,0.45f);
			Vector color = Vector(0.85f,0.85f,0.85f);
			
			float a = 1.0f;
			if(drawpos.z < -1.5f) 
			{
					//color *= 1-Mathematics::calcPosCos(-1*p->pos.z, 2.3f, 4.2f);
					a	  *= 1-Mathematics::calcPosCos(-1*p->pos.z, 3.6f, 5.2f);
			}
		

			glPushMatrix();

				const float size = p->size;

				Matrix rotate;
				rotate.makeRotation(pos*p->rotation.x, pos*p->rotation.y, pos*p->rotation.z);
	
				Vector v1 = x*-size - y*size;
				Vector v2 = x*size  - y*size;
				Vector v3 = x*size  + y*size;
				Vector v4 = x*-size + y*size;

				Vector normal = Vector(0,0,1) * rotate;
				
				const float lightMod = 0.4f+0.6f*fabsf(normal.dotProduct(light));

				glColor4f(color.x*lightMod, color.y*lightMod, color.z*lightMod, 1); 

				v1*= rotate;
				v2*= rotate;
				v3*= rotate;
				v4*= rotate;

				// TODO: fix me
				const float m = (1 + n%25) * 2.4f;
				const float t = pos * 0.0014f;
				const float xx = 0.3f*cosf(m*t*11)+1.1f*sinf(m*t*9)+0.32f*cosf(m*t*11); 
				const float yy = 0.3f*cosf(m*t*5)+1.6f*sinf((-0.9f)*m*t*18)+0.82f*cosf(m*t*8); 
				const float zz = 0.3f*cosf(m*t*32)+0.38f*sinf(m*t*13)+0.82f*cosf((-0.6f)*m*t*15); 
				Vector offset = Vector(xx, yy, zz);

				v1+=p->pos + offset;
				v2+=p->pos + offset;
				v3+=p->pos + offset;
				v4+=p->pos + offset;
				

				glBegin(GL_QUADS);
					glTexCoord2f(0, 0);
					glVertex3fv((float *)&v1);
					glTexCoord2f(1, 0);
					glVertex3fv((float *)&v2);
					glTexCoord2f(1, 1);
					glVertex3fv((float *)&v3);
					glTexCoord2f(0, 1);
					glVertex3fv((float *)&v4);
				glEnd();

			glPopMatrix();

		}
	} while(list->goForward());

/**/
}


void Myrsky::renderScene(float pos, float alpha)
{
	glLoadIdentity();

    updateParticles(pos);

	lookAt_();
	drawScene(pos, alpha);

    RenderReflection(pos, alpha);
    RenderRefractionAndDepth(pos, alpha);

    //reset viewport to screensize
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

	lookAt_();

	//filter.init();
	glEnable(GL_DEPTH_TEST);

		RenderWater(pos, alpha);

		drawScene(pos, alpha);


	glDisable(GL_DEPTH_TEST);
	//filter.glow(2, 0.004f, 0.004f, 1.0f, 0.98f);
}

Myrsky::Myrsky()
{	
/*
	lastTime = -1;
	lastAdd = -1;
	list = new Lista2();
/**/

	trigger = new TriggerSystem();
	trigger->add(158801, 159851);
	trigger->add(171743, 172093);
	trigger->add(172031, 172581);
	trigger->add(172567, 173617);
	trigger->add(179498, 180548);
	trigger->add(180833, 180983);
	trigger->add(183778, 184228);
	trigger->add(184220, 185270);
	trigger->add(186294, 187344);


    int i;
    maxparticles = 1400;
	
    particles = new MyrskyParticle[maxparticles];

    for (i = 0; i < maxparticles; i++)
    {
        particles[i].active = false;
    }

    taikacount = 370;

    taiat = new MyrskyTaika*[taikacount];
    for (i = 0; i < taikacount; i++)
    {
        taiat[i] = new MyrskyTaika();
        taiat[i]->st = 0.5f+0.5f*powf(Mathematics::randFloat(), 0.46f);
        taiat[i]->et = taiat[i]->st + Mathematics::randBetween(0.1f, 0.2f);
        taiat[i]->radius = 12*(0.5f+0.5f*Mathematics::randFloat())*(1.0f - 0.9f*taiat[i]->st);
        taiat[i]->y = Mathematics::randBetween(1, 5);
        taiat[i]->width = Mathematics::randFloat()*(Mathematics::randBetween(0.3f, 1.5f))*3.141592f;

        Vector c1, c2;
        switch(rand()%4)
        {
            case 0:
            {
                //vihreä
                c1 = Vector(0.15f, 0.5f, 0.25f);
                c2 = Vector(0.14f, 0.8f, 0.24f);
            } break;
            case 1:
            {
                //keltainen
                c1 = Vector(0.9f, 0.7f, 0.3f);
                c2 = Vector(1.0f, 0.8f, 0.3f);

            } break;
            case 2:
            {
                //oranssi
                c1 = Vector(0.8f, 0.4f, 0.1f);
                c2 = Vector(1.0f, 0.5f, 0.1f);
            } break;

            case 3:
            {
                //punainen
                c1 = Vector(0.8f, 0.2f, 0.1f);
                c2 = Vector(1.0f, 0.3f, 0.1f);
            } break;
        }

        float coloralpha = 0.5f;
        float colort = Mathematics::randFloat();
        taiat[i]->color = (c1 * (1-colort) + c2*colort)*coloralpha;
        taiat[i]->phase = Mathematics::randFloat();
        taiat[i]->speed = Mathematics::randBetween(4, 7);
    }
}

Myrsky::~Myrsky()
{
    delete [] particles;
/*
    list->destroy();
	delete list;
/**/
}

bool Myrsky::init(unsigned long s, unsigned long e)
{

	// kameran liike
	// Vector cam = Vector(-10-pos*16.0f, pos*2.5f, sinf(pos*1.6f)*2.5f-5);

/*
	MyrskyP *p;
	int i;
	Vector offset_start = Vector(-15,-15,-10);
	for(i=0; i<PARTICLE_COUNT; i++) 
	{
		//Vector addpos = Mathematics::randVector(60,15,10) + offset_start;
		float pos = i/1004.0f;
		Vector addpos = Vector(-20-pos*56.0f, 
								3 + sinf(pos*1.6f)*5.5f,					
								pos*2.5f) + Mathematics::randVector(48.0f, 0.0f, 38.0f ); 
								//sinf(pos*1.6f)*2.5f-5) + Mathematics::randVector(28.0f, 18.0f, 0.0f);
		p = new MyrskyP();
		p->init(addpos);
		list->add(p);
	}
/**/

	startTime = s;
	endTime = e;
	return true;
}

/*
void MyrskyP::init(Vector start) 
{
	this->pos = start;
	this->rotation = Mathematics::randVector()*125.0f;
	this->size = 0.1f+Mathematics::randFloat()*0.25f;
}
/**/