#define NO_SDL_GLEXT

#include <GL/glew.h>
#include <SDL/SDL_OpenGL.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include <math.h>

#include "demo_script.h"
#include "demo_textures.h"
#include "demo_shaders.h"
#include "demo_screen.h"

#include "part_intro.h"

const int n_cubes = 256;
cube cubes[n_cubes];

GLuint palTexture;
GLuint sinTexture;

GLuint polTexture;

bool intro_init = false;

GLint pl_timer;
GLint pl_ctex;
GLint pl_stex;

GLint pr_timer;
GLint pr_ptex;
GLint pr_ctex;
GLint pr_stex;

int programm0 = PR_PLASMA;
int programm1 = PR_POLAR;

void init_cubes()
{
	for (int i=0; i<n_cubes; i++)
	{
		cubes[i].size = 1.0f;
		cubes[i].xp = 0.0f;
		cubes[i].yp = 0.0f;
		cubes[i].zp = -8.0f;
		cubes[i].xr = 42.4f;
		cubes[i].yr = 24.3f;
		cubes[i].zr = 35.2f;
	}
}

void intro_precalcs()
{
	palTexture = GenTexture(256, 1, GEN_PALLETTE, 1);
	sinTexture = GenTexture(256, 1, GEN_SINE, 1);
	polTexture = GenTexture(1024, 1024, GEN_POLAR, 2);

	glClearColor(0.25f, 0.0f, 0.0f, 0.0f);

	pl_timer = MyGetUniformLocation(programm0, "ptimer");
	pl_ctex = MyGetUniformLocation(programm0, "ctex");
	pl_stex = MyGetUniformLocation(programm0, "stex");

	pr_timer = MyGetUniformLocation(programm1, "ptimer");
	pr_ptex = MyGetUniformLocation(programm1, "ptex");
	pr_ctex = MyGetUniformLocation(programm1, "ctex");
	pr_stex = MyGetUniformLocation(programm1, "stex");

	init_cubes();

    intro_init = true;
}

void DrawCube(cube *cb)
{
	glLoadIdentity();
	glTranslatef(cb->xp, cb->yp, cb->zp);
	glRotatef(cb->xr, 1.0f, 0.0f, 0.0f);
	glRotatef(cb->yr, 0.0f, 1.0f, 0.0f);
	glRotatef(cb->zr, 0.0f, 0.0f, 1.0f);


	float l = cb->size;

	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-l, -l, l);
		glTexCoord2f(1.0f, 0.0f); glVertex3f( l, -l, l);
		glTexCoord2f(1.0f, 1.0f); glVertex3f( l, l, l);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-l, l, l);
	glEnd();

	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(l, -l, -l);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-l, -l, -l);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-l, l, -l);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(l, l, -l);
	glEnd();

	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(l, -l, l);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(l, -l, -l);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(l, l, -l);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(l, l, l);
	glEnd();

	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-l, -l, -l);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(-l, -l, l);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(-l, l, l);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-l, l, -l);
	glEnd();

	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-l, l, l);
		glTexCoord2f(1.0f, 0.0f); glVertex3f( l, l, l);
		glTexCoord2f(1.0f, 1.0f); glVertex3f( l, l, -l);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-l, l, -l);
	glEnd();

	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-l, -l, -l);
		glTexCoord2f(1.0f, 0.0f); glVertex3f( l, -l, -l);
		glTexCoord2f(1.0f, 1.0f); glVertex3f( l, -l, l);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-l, -l, l);
	glEnd();
}

void DrawCubes(int ptime)
{
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);
	glEnable(GL_TEXTURE_1D);

	cubes[0].xr = ptime * 0.05f;
	cubes[0].yr = ptime * 0.06f;
	cubes[0].zr = ptime * 0.07f;
	cubes[0].zp = -8.0f + sin(ptime * 0.00025f) * 6.0f;

	MyUseProgram(programm0);
	MyUniform1f(pl_timer, (float)ptime);
	MyUniform1i(pl_ctex, 0);
	MyUniform1i(pl_stex, 1);

	glActiveTextureARB(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_1D, palTexture);
	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER,GL_NEAREST);
	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);

	glActiveTextureARB(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_1D, sinTexture);
	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);

	DrawCube(&cubes[0]);
}

void DrawQuad(float l)
{
	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex2f(-l, -l);
		glTexCoord2f(1.0f, 0.0f); glVertex2f( l, -l);
		glTexCoord2f(1.0f, 1.0f); glVertex2f( l, l);
		glTexCoord2f(0.0f, 1.0f); glVertex2f(-l, l);
	glEnd();
}

void DrawPolarSun(int ptime)
{
	MyUseProgram(programm1);
	MyUniform1f(pr_timer, (float)ptime);
	MyUniform1i(pr_ptex, 0);
	MyUniform1i(pr_ctex, 1);
	MyUniform1i(pr_stex, 2);

	glDisable(GL_DEPTH_TEST);
	glDisable(GL_CULL_FACE);
	glEnable(GL_TEXTURE_2D);

	glActiveTextureARB(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, polTexture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);

	glActiveTextureARB(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_1D, palTexture);
	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER,GL_NEAREST);
	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);

	glActiveTextureARB(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_1D, sinTexture);
	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);

	glLoadIdentity();
	glTranslatef(0.0f, 0.0f, -3.4f * 16.0f);

	glRotatef(ptime / 64.0f, 0.0f, 0.0f, 1.0f);
	DrawQuad(16.0f);
}

void intro_run(int ptime)
{
	if (!intro_init) intro_precalcs();

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	DrawPolarSun(ptime);

	DrawCubes(ptime);
}
