#pragma once

#ifndef FIGURE_H
#define FIGURE_H

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <map>
#include <vector>

#include<glm/glm.hpp>
#include<glm/gtc/matrix_transform.hpp>
#include<glm/gtc/type_ptr.hpp>

#include"shader.h"

using namespace std;
using namespace glm;

//目前只支持简单图形，圆形或球体请使用纹理或模型。



//---------------------------2d---------------------------





//---------------------------3d---------------------------
class Cube {
public:
	vec3 pos = vec3(0.0, 0.0, 0.0);
	float zoom = 1.0;

	GLuint tex;
	vec4 col;

	Cube(GLuint tex_, vec3 pos_= vec3(0.0,0.0,0.0), float zoom_ = 1.0, int xTexNum = 1,int yTexNum = 1) {
		tex = tex_;
		pos = pos_;
		zoom = zoom_;

		float cubeVertices[] = {
			// positions          // texture Coords
			-0.5f, -0.5f, -0.5f,  0.0f,    0.0f,
			 0.5f, -0.5f, -0.5f,  xTexNum, 0.0f,
			 0.5f,  0.5f, -0.5f,  xTexNum, yTexNum,
			 0.5f,  0.5f, -0.5f,  xTexNum, yTexNum,
			-0.5f,  0.5f, -0.5f,  0.0f,    yTexNum,
			-0.5f, -0.5f, -0.5f,  0.0f,    0.0f,

			-0.5f, -0.5f,  0.5f,  0.0f,    0.0f,
			 0.5f, -0.5f,  0.5f,  xTexNum, 0.0f,
			 0.5f,  0.5f,  0.5f,  xTexNum, yTexNum,
			 0.5f,  0.5f,  0.5f,  xTexNum, yTexNum,
			-0.5f,  0.5f,  0.5f,  0.0f,    yTexNum,
			-0.5f, -0.5f,  0.5f,  0.0f,    0.0f,

			-0.5f,  0.5f,  0.5f,  xTexNum, 0.0f,
			-0.5f,  0.5f, -0.5f,  xTexNum, yTexNum,
			-0.5f, -0.5f, -0.5f,  0.0f,    yTexNum,
			-0.5f, -0.5f, -0.5f,  0.0f,    yTexNum,
			-0.5f, -0.5f,  0.5f,  0.0f,    0.0f,
			-0.5f,  0.5f,  0.5f,  xTexNum, 0.0f,

			 0.5f,  0.5f,  0.5f,  xTexNum, 0.0f,
			 0.5f,  0.5f, -0.5f,  xTexNum, yTexNum,
			 0.5f, -0.5f, -0.5f,  0.0f,    yTexNum,
			 0.5f, -0.5f, -0.5f,  0.0f,    yTexNum,
			 0.5f, -0.5f,  0.5f,  0.0f,    0.0f,
			 0.5f,  0.5f,  0.5f,  xTexNum, 0.0f,

			-0.5f, -0.5f, -0.5f,  0.0f,    yTexNum,
			 0.5f, -0.5f, -0.5f,  xTexNum, yTexNum,
			 0.5f, -0.5f,  0.5f,  xTexNum, 0.0f,
			 0.5f, -0.5f,  0.5f,  xTexNum, 0.0f,
			-0.5f, -0.5f,  0.5f,  0.0f,    0.0f,
			-0.5f, -0.5f, -0.5f,  0.0f,    yTexNum,

			-0.5f,  0.5f, -0.5f,  0.0f,    yTexNum,
			 0.5f,  0.5f, -0.5f,  xTexNum, yTexNum,
			 0.5f,  0.5f,  0.5f,  xTexNum, 0.0f,
			 0.5f,  0.5f,  0.5f,  xTexNum, 0.0f,
			-0.5f,  0.5f,  0.5f,  0.0f,    0.0f,
			-0.5f,  0.5f, -0.5f,  0.0f,    yTexNum
		};


		glGenVertexArrays(1, &cubeVAO);
		glGenBuffers(1, &cubeVBO);
		glBindVertexArray(cubeVAO);
		glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
		glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
		glEnableVertexAttribArray(0);
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
		glEnableVertexAttribArray(1);
		glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
	}

	void Draw(Shader shader, Camera camera, float rotateAngle = 0.0, vec3 rotateDirection = vec3(0.0)) {
		shader.use();

		glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, viewMinDis, viewMaxDis);
		glm::mat4 view = camera.GetViewMatrix();

		mat4 model = mat4(1.0);
		model = glm::translate(model, pos);
		model = scale(model, vec3(zoom));

		if (rotateAngle != 0) {
			model = glm::rotate(model, rotateAngle, rotateDirection);
		}
		
		shader.setMat4("model", model);

		shader.setMat4("projection", projection);
		shader.setMat4("view", view);

		glBindVertexArray(cubeVAO);
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, tex);
		glDrawArrays(GL_TRIANGLES, 0, 36);
	}

private:
	unsigned int cubeVAO, cubeVBO;
};





class Plate {
public:
	unsigned int tex;
	vec4 col;
	vec3 Rotate = vec3(0.0f, 0.0f, 0.0f);

	Plate(unsigned int tex_,float left,float top,float right,float bottom,float offset, int xTexNum = 1,int yTexNum = 1) {
		tex = tex_;

		float plateVertices[30] = {
			// positions          // texture Coords 
			right, offset, top,     xTexNum, 0.0f,
			left,  offset, top,     0.0f,    0.0f,
			left,  offset, bottom,  0.0f,    yTexNum,

			right, offset, top,     xTexNum, 0.0f,
			left,  offset, bottom,  0.0f,    yTexNum,
			right, offset, bottom,  xTexNum, yTexNum
		};

		glGenVertexArrays(1, &plateVAO);
		glGenBuffers(1, &plateVBO);
		glBindVertexArray(plateVAO);
		glBindBuffer(GL_ARRAY_BUFFER, plateVBO);
		glBufferData(GL_ARRAY_BUFFER, sizeof(plateVertices), &plateVertices, GL_STATIC_DRAW);
		glEnableVertexAttribArray(0);
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
		glEnableVertexAttribArray(1);
		glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
		glBindVertexArray(0);
	}

	void Draw(Shader shader, Camera camera, float rotateAngle = 0.0f, vec3 rotateDirection = vec3(0.0f)) {
		shader.use();

		glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, viewMinDis, viewMaxDis);
		glm::mat4 view = camera.GetViewMatrix();
		glm::mat4 model;
		if (rotateAngle != 0) {
			model = glm::rotate(glm::mat4(1.0f), rotateAngle, rotateDirection);
		}
		else {
			model = glm::mat4(1.0f);
		}

		shader.setMat4("projection", projection);
		shader.setMat4("view", view);
		shader.setMat4("model", model);

		glBindVertexArray(plateVAO);
		glBindTexture(GL_TEXTURE_2D, tex);
		glDrawArrays(GL_TRIANGLES, 0, 6);
	}
private:
	unsigned int plateVAO, plateVBO;
};


#endif