#include "../Framework/Framework.h"
#include "../Framework/Util/OpenGLModel.h"

char *drawModeNames[3] = { "DPS,    lowres", "Normal, lowres", "Normal, hires" };

class MainApp : public OpenGLApp {
protected:
	OpenGLModel *lowresModel, *hiresModel;

	Vertex lightPos;
	int drawMode;

	TextureID base;
	ShaderID dpsVS, dpsFS, normalVS, normalFS;

	void drawObject();
public:
	void setKey(UINT key, bool value);
	void selectPixelFormat(PixelFormat &pixelFormat);

	bool init();
	bool exit();
	bool load();
	bool unload();
	bool drawFrame();

	void resetCamera();
};

void MainApp::setKey(UINT key, bool value){
	OpenGLApp::setKey(key, value);

	if (value){
		switch (key){
        case '1':
			drawMode = 0;
            break;
        case '2':
			drawMode = 1;
            break;
        case '3':
			drawMode = 2;
            break;
		}		
	}	
}


void MainApp::resetCamera(){
	position = Vertex(80, 70, -30);
	Wx = 0.3f;
	Wy = 1.24f;
	Wz = 0;
}

void MainApp::selectPixelFormat(PixelFormat &pixelFormat){
	pixelFormat.redBits   = 8;
	pixelFormat.greenBits = 8;
	pixelFormat.blueBits  = 8;
	pixelFormat.alphaBits = 0;

	pixelFormat.depthBits = 24;
}

bool MainApp::init(){
	drawMode = 0;
	speed = 512;

	return true;
}

bool MainApp::exit(){
	return true;
}

bool MainApp::load(){
	String supported, missing;

    if (GL_ARB_fragment_program) supported += "GL_ARB_fragment_program\n"; else missing += "GL_ARB_fragment_program\n";
    if (GL_ARB_vertex_program)   supported += "GL_ARB_vertex_program\n";   else missing += "GL_ARB_vertex_program\n";

    if (missing.getLength() > 0){
        ALERT("The following required OpenGL extensions are supported:\n\n" + supported +
			  "\nToo bad, these required OpenGL extensions aren't supported by the graphic card and driver you're using:\n\n" + missing +
              "\nThis application will now exit.", "Missing extensions");
        return false;
    }



	lowresModel = new OpenGLModel();
	hiresModel = new OpenGLModel();

	lowresModel->loadFromFile("../Models/Bunny/BunnyLowRes.hmdl");
	hiresModel->loadFromFile("../Models/Bunny/BunnyHiRes.hmdl");

	((OpenGLBatch *) lowresModel->getBatch(0))->uploadToVertexBuffer();
	((OpenGLBatch *) hiresModel->getBatch(0))->uploadToVertexBuffer();


	base = renderer->addTexture("../Models/Bunny/bunnyBump.png");
	textTexture = renderer->addTexture("../Textures/font2.dds");

	projection.loadProjectionMatrix(80 * PI / 180, 0.75f, 0.1f, 6000);

	dpsVS = renderer->addVertexShader("DPS.vsh");
	if (glGetError() != GL_NO_ERROR) ALERT((char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB), "Error");

	dpsFS = renderer->addFragmentShader(GL_FRAGMENT_PROGRAM_ARB, "DPS.fsh");
	if (glGetError() != GL_NO_ERROR) ALERT((char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB), "Error");

	normalVS = renderer->addVertexShader("Normal.vsh");
	if (glGetError() != GL_NO_ERROR) ALERT((char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB), "Error");

	normalFS = renderer->addFragmentShader(GL_FRAGMENT_PROGRAM_ARB, "Normal.fsh");
	if (glGetError() != GL_NO_ERROR) ALERT((char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB), "Error");

	return true;
}

bool MainApp::unload(){
	delete lowresModel;
	delete hiresModel;

	return true;
}

void MainApp::drawObject(){
    glMatrixMode(GL_MODELVIEW);
	glLoadMatrixf(modelView);

	glMatrixMode(GL_PROJECTION);
	glLoadMatrixf(projection);

	if (drawMode == 0){
		renderer->setTextures(base);
		renderer->setVertexShader(dpsVS);
		renderer->setFragmentShader(dpsFS);
	} else {
		renderer->setVertexShader(normalVS);
		renderer->setFragmentShader(normalFS);
	}
	renderer->apply();

	lightPos = Vertex(100 * sinf(0.2f * currTime), 100, -100 * cosf(0.2f * currTime));

	//glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 0, 50, 100, -100, 0);
	glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 0, lightPos.x, lightPos.y, lightPos.z, 0);
	glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 1, position.x, position.y, position.z, 0);

	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);
	glFrontFace(GL_CW);

	if (drawMode == 2){
		hiresModel->draw();
	} else {
		lowresModel->draw();
	}

	glDisable(GL_CULL_FACE);
}

bool MainApp::drawFrame(){
	//glClearColor(0.4f, 0.4f, 0.4f, 0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);

	glMatrixMode(GL_PROJECTION);
	glLoadMatrixf(projection);

	modelView.loadRotateZXY(-Wx, -Wy, -Wz);
	modelView.translate(-position);

    glMatrixMode(GL_MODELVIEW);
	glLoadMatrixf(modelView);

	drawObject();


	if (showFPS){
		unsigned int nTris = ((drawMode == 2)? hiresModel : lowresModel)->getBatch(0)->getIndexCount() / 3;
		char str[32];
		sprintf(str, "%d Triangles", nTris);

		renderer->setBlending(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		renderer->setTextures(textTexture);
		renderer->apply();

		drawText(drawModeNames[drawMode], 0.55f, 0.02f, 0.03f, 0.05f);
		drawText(str, 0.55f, 0.1f, 0.03f, 0.05f);
	}

	return true;
}

DECLARE_MAIN_APP(MainApp)
