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

#include <math.h>

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


LuolaFragmentShader::LuolaFragmentShader(char *filename)
{
    fs = new FragmentShader(filename);
    texture = cgGetNamedParameter(fs->program, "texture");
    texture2 = cgGetNamedParameter(fs->program, "texture2");
	time = cgGetNamedParameter(fs->program, "time");
}
LuolaFragmentShader::~LuolaFragmentShader()
{
    delete fs;
}

void LuolaFragmentShader::initFrame(float pos)
{
//    cgGLSetTextureParameter(texture, dmsGetTexture("nebula5_env.jpg")->getID());
    cgGLSetTextureParameter(texture, dmsGetTexture("nebula5.jpg")->getID());
    cgGLSetTextureParameter(texture2, dmsGetTexture("taivas.jpg")->getID());
    cgGLSetParameter1f(time, pos);
	cgGLEnableTextureParameter(texture);
	cgGLEnableTextureParameter(texture2);
}

void LuolaFragmentShader::freeFrame()
{
    cgGLDisableTextureParameter(texture);   
    cgGLDisableTextureParameter(texture2);   
}
void LuolaFragmentShader::bind()
{
    fs->bind();
}

void Luola::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);


#define Luola_BLUR

#ifndef Luola_BLUR
	renderScene(pos, alpha);
#else

    filter.prepare512();
    renderScene(pos, alpha);
    filter.glow(1, 7, 0.006f, 0.13f, alpha);


#endif

}

void Luola::renderScene(float pos, float alpha)
{
    int i;

    static bool rottrigger1 = false;
    static bool rottrigger2 = false;
    static bool rottrigger3 = false;
    static int phase = 0;

    float currentpos = 0.0f;
    const float alku = 0.0f;
    const float l1 = 0.25f;
    const float l2 = 0.50f;
    const float l3 = 0.75f;
    const float loppu = 1.00f;

    if (pos >= alku && pos <= l1)
    {
        currentpos = Mathematics::calcPosFloat(pos, alku, l1);
        phase = 0;
    }
    if (pos > l1 && pos <= l2)
    {
        currentpos = Mathematics::calcPosFloat(pos, l1, l2);
        phase = 1;
    }
    if (pos > l2 && pos <= l3)
    {
        currentpos = Mathematics::calcPosFloat(pos, l2, l3);
        phase = 2;
    }
    if (pos > l3)
    {
        currentpos = Mathematics::calcPosFloat(pos, l3, loppu);
        phase = 3;
    }

    Vector objectpos = Vector(0, -4+pos*35, 0);
    Vector or = Vector(0.4f, 0.8f, 0.1f);

    static Vector campositions[4] =
    {
        Vector(0, 2, -5.0f),
        Vector(0, 1, -2.0f),
        Vector(3, 13, -3.0f),
        Vector(-1, 19, -1.0f),
    };

    static Vector camdeltas[4] = 
    {
        Vector(-2, 1.3f, 2),
        Vector(-2, 1.3f, 2)*0.75f,
        Vector(-2, 1.3f, 2)*0.50f,
        Vector(-2, 1.3f, 2)*0.25f,
    };
    
    static Vector camtargets[4] = 
    {
        Vector(0, 0.2f, 0),
        Vector(0, 10, 0),
        Vector(0, 13.0f, 0),
        Vector(0, 18.0f, 0),

    };

    Vector cp = campositions[phase] + camdeltas[phase]*pos;
    Vector ct = objectpos;//camtargets[phase];

   	glLoadIdentity();
    gluLookAt(cp.x, cp.y, cp.z, ct.x, ct.y, ct.z, 0.7f, 1, 0);

    myEnable(MY_TEXTURE_2D);
    myEnable(MY_DEPTH_TEST);
    myDisable(MY_BLEND);
	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
	myEnable(MY_TEXTURE_GEN_S);
	myEnable(MY_TEXTURE_GEN_T);


    glBindTexture(GL_TEXTURE_2D, dmsGetTexture("nebula5.jpg")->getID());

    int polycount = (int)(totalpolycount);//*Mathematics::calcPosFloat(pos, 0.0f, 0.11f));
    glBegin(GL_TRIANGLES);
    const float tunnelicolor = 0.3f;//radial[i]);
    glColor4f(tunnelicolor, tunnelicolor, tunnelicolor,1);
    for (i=0;i<polycount;i++)
    {
        glNormal3fv((float *)&faces[i].normal);
        glVertex3fv((float *)&vertices[faces[i].a].position);
        glVertex3fv((float *)&vertices[faces[i].b].position);
        glVertex3fv((float *)&vertices[faces[i].c].position);
    }
    glEnd();
 
    
    
    T3D *object1 = dmsGetObject("blob2.t3d");

    int objectvertexcount = object1->getVertexCount();
    int objectfacecount = object1->getFaceCount();

    T3DFace *objectfaces = object1->getFaceArray();
    T3DVertex *objectvertices = object1->getVertexArray();

    myEnable(MY_TEXTURE_2D);
    myEnable(MY_DEPTH_TEST);
    myDisable(MY_BLEND);

	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
	myEnable(MY_TEXTURE_GEN_S);
	myEnable(MY_TEXTURE_GEN_T);

    glColor4f(1,1,1,1);

    glPushMatrix();
    const float os = 0.0017f;

    glTranslatef(objectpos.x, objectpos.y, objectpos.z);
    glRotatef(pos*570, or.x, or.y, or.z);
    glScalef(os, os, os);


    glBindTexture(GL_TEXTURE_2D, dmsGetTexture("taivas.jpg")->getID());
    glBegin(GL_TRIANGLES);
    for (i=0;i<objectfacecount;i++)
    {
        glNormal3fv((float *)&objectfaces[i].normal);
        glVertex3fv((float *)&objectvertices[objectfaces[i].a].position);
        glVertex3fv((float *)&objectvertices[objectfaces[i].b].position);
        glVertex3fv((float *)&objectvertices[objectfaces[i].c].position);
    }
    glEnd();

    glPopMatrix();
    

    fs->initFrame(pos);
    fs->bind();
    cg.enableFragmentShader();


    T3D *object2 = dmsGetObject("gsphere.t3d");

    objectvertexcount = object2->getVertexCount();
    objectfacecount = object2->getFaceCount();

    objectfaces = object2->getFaceArray();
    objectvertices = object2->getVertexArray();

    myEnable(MY_TEXTURE_2D);
    myEnable(MY_DEPTH_TEST);
    myDisable(MY_BLEND);

	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
	myEnable(MY_TEXTURE_GEN_S);
	myEnable(MY_TEXTURE_GEN_T);

    const float taustacolor = 0.3f*Mathematics::calcPosFloat(pos, 0.27f, 0.41f);
    if (taustacolor > 0.0001f)
    {
        glColor4f(taustacolor, taustacolor, taustacolor, taustacolor);

        glPushMatrix();
        glRotatef(pos*100, 1, 1, 1);
        glRotatef(60, 1, 0.4f, 0.1f);
        glScalef(2.5f,2.5f,2.5f);

//        glBindTexture(GL_TEXTURE_2D, dmsGetTexture("nebula5_env.jpg")->getID());
        glBegin(GL_TRIANGLES);
        for (i=0;i<objectfacecount;i++)
        {
            glNormal3fv((float *)&objectfaces[i].normal);
            glVertex3fv((float *)&objectvertices[objectfaces[i].a].position);
            glVertex3fv((float *)&objectvertices[objectfaces[i].b].position);
            glVertex3fv((float *)&objectvertices[objectfaces[i].c].position);
        }
        glEnd();

        glPopMatrix();
    }

    cg.disableFragmentShader();
    fs->freeFrame();
   
    
    myDisable(MY_TEXTURE_GEN_S);
    myDisable(MY_TEXTURE_GEN_T);

}


Luola::Luola()
{
    int i;
    int x, z;
    xres = 40;
    zres = 40;
    vertexcount = xres*zres;
    facecount = xres*zres*2;

    fs = new LuolaFragmentShader("shaders\\fs_luola.cg");

    vertices = new T3DVertex[vertexcount];
    radial = new float[vertexcount];
    faces = new T3DFace[facecount];

    const float scale = 9.0f;
    for (z=0;z<zres;z++)
    {
        for (x=0;x<xres;x++)
        {
            Vector p = Vector((x-xres*0.5f)/xres, 0, (z-zres*0.5f)/zres)*scale;
            vertices[x+z*xres].position = p;

            Vector maxlengthvector = Vector(xres*0.5f, 0, zres*0.5f);
            radial[x+z*xres] = (float)fabs((maxlengthvector.length() - p.length())/maxlengthvector.length());
        }
    }

    totalpolycount = 0;
    int offset = 0;
    for (z=0;z<zres-1;z++)
    {
        for (x=0;x<xres-1;x++)
        {
            faces[offset].a = x+z*xres;
            faces[offset].b = ((x+1)%xres)+((z+1)%zres)*xres;
            faces[offset].c = x+((z+1)%zres)*xres;
            offset++;
            totalpolycount++;
            faces[offset].a = x+z*xres;
            faces[offset].b = ((x+1)%xres)+z*xres;
            faces[offset].c = ((x+1)%xres)+((z+1)%zres)*xres;
            offset++;
            totalpolycount++;
        }
    }

    for (x=0;x<xres;x++)
    {
        for (z=0;z<zres;z++)
        {
            vertices[x+z*xres].position.y = -(float)pow(radial[x+z*xres], 35)*6;
        }
    }


    for (i=0;i<facecount;i++)
    {
        Vector v1 = vertices[faces[i].b].position - vertices[faces[i].a].position;
        Vector v2 = vertices[faces[i].c].position - vertices[faces[i].a].position;
        faces[i].normal = v1.crossProduct(v2).normalize(); //ilman normalisointia? 

    }

}

Luola::~Luola()
{
    delete [] vertices;
    delete [] faces;
    delete [] radial;

}

bool Luola::init(unsigned long s, unsigned long e)
{
	startTime = s;
	endTime = e;
	return true;
}

