/* Copyright (C) 2007  Mikko Sysikaski <mikko.sysikaski@gmail.com>
 * This program is free software distributed under GNU General Public License
 * version 3 or (at your option) any later version.
 * No warranty of any kind is provided. See the accompanying file COPYING for details.
 */

#include "menubg.h"
#include "common.h"
#include <GL/gl.h>
#include <GL/glext.h>
#include <cstring>
#include <cmath>
#include <cstdlib>

#define PI M_PI

namespace {
const int XSIZE=512, YSIZE=512;
const float STARTX=-4.0f/3.0f, STARTY=-1.2f;
const float ENDX=4.0f/3.0f, ENDY=1.2f;
const int MAX_ITER=1000;

const Coord2 juliaCoord[] =
{
	Coord2(0.285f, 0.01f),
	Coord2(0.352f, 0.64f),
	Coord2(-0.726f, 0.188f),
	Coord2(-0.835f, -0.2321f),
	Coord2(0.41f, 0.41f),
	Coord2(-0.1f, 0.84f),
	Coord2(0.335f, 0.0435f),
	Coord2(-0.0002f, 0.7383f),
	Coord2(0.365f, 0.39f),
	Coord2(0.359f, 0.359f),
	Coord2(0.4f, -0.25f),
	Coord2(-0.095f, 0.95f),
	Coord2(-1.0f, 0.31f),
	Coord2(-0.6f, 0.5f),
	Coord2(-0.6f, 0.45f),
	Coord2(0.39f, -0.2f),
	Coord2(-0.76f, 0.19f),
	Coord2(-0.74f, 0.155f)
};
Coord2 juliaC;

const int PSIZE=256;
GLuint palette[PSIZE][3];

void genPalette()
{
	for(int i=0; i<PSIZE; ++i) {
		palette[i][0] = palette[i][1] = GLubyte(64.0f + 63.9f*sin(PI*i/64.0f));
		palette[i][2] = GLubyte(192.0f + 63.9f*sin(PI*i/32.0f));
	}
}
}

MenuBG MenuBG::m_instance;

void MenuBG::doInit()
{
	juliaC = juliaCoord[rand()%(sizeof(juliaCoord)/sizeof(Coord2))];
//	juliaC = juliaCoord[17];
	genPalette();
	float dx = (ENDX-STARTX)/XSIZE;
	float dy = (ENDY-STARTY)/YSIZE;
	GLubyte texture[YSIZE][XSIZE][3] = {};
	float fy=STARTY;
	for(int y=0; y<YSIZE; ++y) {
		float fx = STARTX;
		for(int x=0; x<XSIZE; ++x) {
			setPix(fx, fy, &texture[y][x][0]);
			fx += dx;
		}
		fy += dy;
	}
	glGenTextures(1, &m_texNum);
	glBindTexture(GL_TEXTURE_2D, m_texNum);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, XSIZE, YSIZE, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);

	m_texture = new GLubyte[XSIZE*YSIZE*3];
	memcpy(m_texture, texture, XSIZE*YSIZE*3);
}

void MenuBG::doDraw()
{
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, m_texNum);
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glPushMatrix();
	glLoadIdentity();

	glBegin(GL_QUADS);
	glTexCoord2f(0, 0); glVertex2f(-1, -1);
	glTexCoord2f(1, 0); glVertex2f(1, -1);
	glTexCoord2f(1, 1); glVertex2f(1, 1);
	glTexCoord2f(0, 1); glVertex2f(-1, 1);
	glEnd();

	glPopMatrix();
	glDisable(GL_TEXTURE_2D);
}

void MenuBG::setPix(float x, float y, GLubyte res[3])
{
	float x2=x*x, y2=y*y;
	int i;
	for(i=0; i<MAX_ITER && x2+y2<4.0f; ++i) {
		y = 2.0f*x*y + juliaC.y;
		x = x2 - y2 + juliaC.x;

		x2 = x*x;
		y2 = y*y;
	}
	res[0] = palette[i%PSIZE][0];
	res[1] = palette[i%PSIZE][1];
	res[2] = palette[i%PSIZE][2];
}

void MenuBG::reloadTexture()
{
	glBindTexture(GL_TEXTURE_2D, m_instance.m_texNum);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, XSIZE, YSIZE, 0, GL_RGB,
	             GL_UNSIGNED_BYTE, m_instance.m_texture);
}
