// PerspectiveVectorDisplaySys.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include "pch.h"
#include <iostream>
using namespace std;
#include <fstream>
#include <math.h>
#include <vector>


#include <vector>
#define GLM_ENABLE_EXPERIMENTAL
// glut
#include <GL/glut.h>



// Include GLFW
//#include <GLFW/glfw3.h>
//GLFWwindow* window;

// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtx/norm.hpp>
#include <glm/gtx/spline.hpp>
#include <glm/gtx/string_cast.hpp>

using namespace glm;


//================================
// global variables (Animation Lab 0)
//================================
// screen size
int g_screenWidth = 0;
int g_screenHeight = 0;

// frame index
int g_frameIndex = 0;

int rcount = 0;

//declare my global variables
ifstream inFile;
int numPoints;
int numPolygons;

class coordinates{
public:
	double x;
	double y;
	double z;
};
coordinates* points;

mat4 model;
mat4 view;
mat4 pers;

//double product[4][4];
//double vector[4];



void parseInputFile() {
	inFile.open("C:\\Users\\Erin\\Downloads\\D_files\\house.d.txt");
	if (!inFile) {
		cerr << "Unable to open file house.d.txt";
		exit(1);
	}
	string firstWord;
	inFile >> firstWord; //throw away first word "data"
	inFile >> numPoints;
	inFile >> numPolygons;

	points = new coordinates[numPoints];
	int* polygons = new int[numPolygons];

	for (int i = 0; i < numPoints; i++) {
		inFile >> points[i].x;
		inFile >> points[i].y;
		inFile >> points[i].z;
	}

	int counter;
	std::vector< std::vector<double>> polygonList(numPolygons);
	double val;


	for (int i = 0; i < numPolygons; i++) {
		inFile >> counter;
		for(int j = 0; j < counter; j++) {
			inFile >> val;
			polygonList[i].push_back(val);
		}
	}
}

vec4 setVector(coordinates currPoint) {
	vec4 vector;
	vector[0] = currPoint.x;
	vector[1] = currPoint.y;
	vector[2] = currPoint.z;
	vector[3] = 1;
	return vector;
}

void setModel() {
	
	model[0] = vec4(1, 0, 0, 0);
	model[1] = vec4(0, 1, 0, 0);
	model[2] = vec4(0, 0, 1, 0);
	model[3] = vec4(0, 0, 0, 1);
}

double normalize(coordinates N) {
	double result;
	result = N.x*N.x + N.y*N.y + N.z*N.z;
	result = sqrt(result);
	return result;
}

coordinates crossProduct(coordinates U, coordinates N) {
	coordinates result;
	result.x = U.y * N.z - (U.z * N.y);
	result.y = U.z * N.x - (U.x * N.z);
	result.z = U.x * N.y - (U.y * N.x);
	return result;
}

coordinates scale(coordinates in) {
	in.x = in.x * -1;
	in.y = in.y * -1;
	in.z = in.z * -1;
	return in;
}

void setView() {//pRef will come in as the current point (xl, yl, zl)
	coordinates pRef;
	pRef.x = 0;
	pRef.y = 0;
	pRef.z = 0;
	
	coordinates vPrime;
	vPrime.x = 0;
	vPrime.y = 1;
	vPrime.z = 0;

	coordinates C;
	C.x = 0;
	C.y = 0;
	C.z = -10;

	coordinates N;
	coordinates U;
	coordinates V;

	N.x = (pRef.x - C.x);
	N.y = (pRef.y - C.y);
	N.z = (pRef.z - C.z);
	
	double result;
	result = normalize(N);

	N.x = (N.x / result);
	N.y = (N.y / result);
	N.z = (N.z / result);

	U = crossProduct(N, vPrime);

	result = normalize(U);
	U = scale(U);
	
	U.x = (U.x / result);
	U.y = (U.y / result);
	U.z = (U.z / result);

	V = crossProduct(U, N);
	V = scale(V);

	

	view[0] = vec4(U.x, V.x, N.x, 0);
	view[1] = vec4(U.y, V.y, N.y, 0);
	view[2] = vec4(U.z, V.z, N.z, 0);
	view[3] = vec4(-C.x, -C.y, -C.z, 1);
}

void setPerspective(double d, double h, double f) {
	
	pers[0] = vec4((d / h), 0, 0, 0);
	pers[1] = vec4(0, (d / h), 0, 0);
	pers[2] = vec4(0, 0, (f / (f - d)), 1);
	pers[3] = vec4(0, 0, (-(d*f) / (f - d)), 0);
}

void multMatrix(double arrayA[4][4], double arrayB[4][4]) {
	double product[4][4];
	int i, j, k;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 3; j++)
		{
			product[i][j] = 0;
			for (k = 0; k < 3; k++)
				product[i][j] += arrayA[i][k] *
				arrayB[k][j];
		}
	}
}



vec4 multMatrixByVector(mat4 matrix, vec4 currVec) {
	vec4 product;
	product = matrix * currVec;
	return product;
}

vec4 divideByW(vec4 arrayFinal) {

	arrayFinal[0] = arrayFinal[0] / arrayFinal[3];
	arrayFinal[1] = arrayFinal[1] / arrayFinal[3];
	arrayFinal[2] = arrayFinal[2] / arrayFinal[3];
	return arrayFinal;
}

void Draw() {
	vec4 vec;
	vec4 secVec;
	vec4 thiVec;
	vec4 fouVec;

	parseInputFile();
	setModel();
	setView();
	setPerspective(0.1, 5, 30);

	//DEBUGGER
	for (int i = 0; i < numPoints; i++) {
		vec = setVector(points[i]);
		cout << "Before Transform" << endl;
		cout << vec.x<<" " << vec.y << " " <<vec.z << " " << vec.w << endl;
		secVec = multMatrixByVector(model, vec);
		cout << "By Model" << endl;
		cout << secVec.x << " " << secVec.y << " " << secVec.z << " " << secVec.w << endl;
		thiVec = multMatrixByVector(view, secVec);
		cout << "By View" << endl;
		cout << thiVec.x << " " << thiVec.y << " " << thiVec.z << " " << thiVec.w << endl;
		fouVec = multMatrixByVector(pers, thiVec);
		cout << "By Perspective" << endl;
		cout << fouVec.x << " " << fouVec.y << " " << fouVec.z << " " << fouVec.w << endl;
		//fouVec = divideByW(fouVec);
		//cout << fouVec.x << " " << fouVec.y << " " << fouVec.z << endl;
		
		points[i].x = fouVec.x;
		points[i].y = fouVec.y;	
	}

	glColor3f(1, 1, 1);
	glBegin(GL_LINE_LOOP);
	for (int i = 0; i < numPolygons; i++) {
		double x = points[i].x;
		double y = points[i].y;
		glVertex2f(x, y);
	}
	glEnd();
}

void render(void) {
	// clear buffer
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClearDepth(1.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	Draw();

	// swap back and front buffers
	glutSwapBuffers();

}

int main(int argc, char** argv)
{

	// create opengL window
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(600, 600);
	glutInitWindowPosition(100, 100);
	glutCreateWindow(argv[0]);

	glutDisplayFunc(render);

	glutMainLoop();

	return 0;
		
}