/*
 *  Copyright (C) 2008 Hannu Saransaari
 *
 *  This program is distributed under the terms of the
 *  GNU General Public License.
 *
 *  This file is part of Dave the Ordinary Spaceman.
 *
 *  Dave the Ordinary Spaceman is free software: you can redistribute
 *  it and/or modify it under the terms of the GNU General Public
 *  License as published by the Free Software Foundation, either
 *  version 3 of the License, or (at your option) any later version.
 *
 *  Dave the Ordinary Spaceman is distributed in the hope that it
 *  will be useful, but WITHOUT ANY WARRANTY; without even the
 *  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 *  PURPOSE.  See the GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Dave the Ordinary Spaceman. If not, see
 *  <http://www.gnu.org/licenses/>.
 *
 */

#include "opengl.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void check_error(GLhandleARB id, const char* name)
{
	GLint stat = -1;
	glGetObjectParameterivARB(id, GL_OBJECT_COMPILE_STATUS_ARB, &stat);

	char log[1024];
	GLsizei len;
	glGetInfoLogARB(id, sizeof(log)-1, &len, log);
	assert(len < (int)sizeof(log));
	log[len] = '\0';

	if (len)
		fprintf(stderr, "Error %d in %s:\n%s", stat, name, log);

	if (stat != 1)
		abort();
}

static char buffer[1024*8];
static char buffer2[1024*8];

static void load_file(const char* file_name, char* buf)
{
	static char tmp[1024*8];

	FILE* fp = fopen(file_name, "rt");
	if (!fp)
	{
		fprintf(stderr, "Can't open file %s\n", file_name);
		abort();
	}
	int n = fread(tmp, 1, sizeof(tmp)-1, fp);
	tmp[n] = '\0';
	fclose(fp);

	strcpy(buf, tmp);

	//config.substitute_variables(tmp, buf);
}

GLProgram::GLProgram(const char* vertFile, const char* fragFile)
{
	fprintf(stderr, "Compling shader '%s', '%s'...", vertFile, fragFile);
	prog = glCreateProgramObjectARB();

	load_file("graphics/std.glsl", buffer);

	static const char* src[2] = { buffer, buffer2 };

	/* Load vertex shader. */

	load_file(vertFile, buffer2);

	GLhandleARB vs;
	vs = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
	glShaderSourceARB(vs, 2, src, NULL);
	glCompileShaderARB(vs);

	assert(glGetError() == GL_NO_ERROR);
	check_error(vs, vertFile);

	/* Load fragment shader. */

	load_file(fragFile, buffer2);

	GLhandleARB fs;
	fs = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
	glShaderSourceARB(fs, 2, src, NULL);
	glCompileShaderARB(fs);

	assert(glGetError() == GL_NO_ERROR);
	check_error(fs, fragFile);

	/* Link program. */

	glAttachObjectARB(prog, vs);
	glAttachObjectARB(prog, fs);
	glLinkProgramARB(prog);

	GLint stat;
	glGetObjectParameterivARB(prog, GL_OBJECT_LINK_STATUS_ARB, &stat);
	if (stat != 1)
	{
		static char log[1024];
		GLsizei len;
		glGetInfoLogARB(prog, sizeof(log)-1, &len, log);
		assert(len < (int)sizeof(log));
		log[len] = '\0';
		fprintf(stderr, "Error %d in program %s,%s:\n%s", stat, vertFile, fragFile, log);
		abort();
	}

	assert(glGetError() == GL_NO_ERROR);
	fprintf(stderr, "OK\n");
}

GLProgram::~GLProgram()
{
	// TODO: delete program
}

void GLProgram::use()
{
	assert(prog);
	glUseProgramObjectARB(prog);
}

void GLProgram::unuse()
{
	glUseProgramObjectARB(0);
}

void GLProgram::set_int(const char* n, int v)
{
	glUniform1i(glGetUniformLocationARB(prog, n), v);
}

void GLProgram::set_float(const char* n, float v)
{
	glUniform1f(glGetUniformLocationARB(prog, n), v);
}

void GLProgram::set_vector2(const char* n, const float* v)
{
	glUniform2fv(glGetUniformLocationARB(prog, n), 1, v);
}

void GLProgram::set_vector3(const char* n, const float* v)
{
	glUniform3fv(glGetUniformLocationARB(prog, n), 1, v);
}

void GLProgram::set_matrix4(const char* n, const float* m)
{
	glUniformMatrix4fv(glGetUniformLocationARB(prog, n), 1, GL_FALSE, m);
}

//#include <SDL/SDL.h>
//#include <iostream>
//using namespace std;
void draw_fullscreen_quad(bool i)
{
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();
	glMatrixMode(GL_TEXTURE);
	glPushMatrix();
	glLoadIdentity();

	glBegin(GL_QUADS);
        //const float fix_x = 1.0f / (800.0f * 1.0f);
        const float fix_y = 1.0f / (600.0f * 1.0f);
        //const float high_x = 1.0f - fix_x;
        const float high_y = 1.0f - fix_y;
        //const unsigned int combo = SDL_GetTicks() / 1000;
        //static unsigned int old;
        //if (combo != old) cerr << "combo: " << combo << endl;
        //old=combo;
        const float x0 = 1.0f;//(combo&1) ? (1.0f - fix_x) : 1.0f;
        const float x1 = 1.0f;//(combo&2) ? (1.0f - fix_x) : 1.0f;
        const float y0 = 1.0f;//(combo&4) ? (1.0f - fix_y) : 1.0f;
        const float y1 = 1.0f;//(combo&8) ? (1.0f - fix_y) : 1.0f;
	glTexCoord2f(0.0f, i ? 0.0f : high_y);
	glVertex2f(-1.0f, -1.0f);
	glTexCoord2f(x0, i ? 0.0f : high_y);
	glVertex2f(1.0f, -1.0f);
	glTexCoord2f(x1, i ? y0 : 0.0f);
	glVertex2f(1.0f, 1.0f);
	glTexCoord2f(0.0f, i ? y1 : 0.0f);
	glVertex2f(-1.0f, 1.0f);
	glEnd();

	glMatrixMode(GL_TEXTURE);
	glPopMatrix();
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();
}
