#pragma once
#include <iostream>
#include <string>
#include <vector>
#include "GLM\glm.hpp"
#include "GLM\gtc\matrix_transform.hpp"
#include "MetaModels.h"
#include "LReductor.h"


//class LModel
//{
//public:
//	float *vertexBuffer;
//	unsigned int *indexBuffer;
//	BSize size;
//	glm::mat4 modelMatrix;
//	int height;
//
//	~LModel()
//	{
//		if (vertexBuffer)	free(vertexBuffer);
//		if (indexBuffer)	free(indexBuffer);
//	}
//};



class Generator
{
public:
	Generator();
	/**
	* m_max_angle: the angle between y Axis and new branches spawned by trunk
	*				range: [0,90], default: 45
	* m_sphere_radius_ratio: radio of the upper sphere's radius and bottom sphere's radius
	*				range: [0,1], default: 0.9
	* m_height_radius_ratio: a parameter needed to compute height by sphere's radius
	*				range: [0,1], default: 0.5
	* m_ground_sphere_radius: the radius of the most bottom sphere (the one on the ground)
	*				default: 3
	* Random seeds
	* m_number_of_new_branches_spawned_by_trunk: the number of new branches when spawned by truck
	*				default: 4
	* m_branch_height: refers to how many A after the bifurcation point, branches begin to bifurcate again
	*				default: 3
	* m_leaf_height: refers to after how many A from ground, branches begin to grow leaves
	*				default: 10
	*/
	Generator(float treeSize, float heightRadiusRatio, float radiusRatio, float maxAngle, float turbulenceAngle, int branchNumber, int branchHeight, float p_furcate, float p_leaf, int leafHeight, int randomSeed);
	~Generator();
	/**
	* times: the number of L-system's iterations 
	*/
	void generate(int times);
	void generateOnce();

	// int getBufferLength();
	//void bindBuffer(LModel *modelbuffer);
	void bindBranchBuffers(float *vbuffer, unsigned int *ibuffer);
	void bindLeafBuffers(float *vbuffer, unsigned int *ibuffer);
	BFSize getBranchBufferSize();
	BFSize getLeafBufferSize();
	void transferToBranchBuffer();
	void transferToLeafBuffer();
	void generateTreeModel();
	void saveAsObj();

private:
	
	float m_max_angle, m_sphere_radius_ratio, m_height_radius_ratio, m_tree_size;
	int m_branch_number_of_new_branches_spawned_by_one_trunk, m_branch_number_of_new_branches, m_leaf_height;
	float minShrinkRate;
	float m_turbulence_angle;
	unsigned int randomSeed;
	std::string sentence;
	float m_branch_number_of_new_branches_fluctuation;
	float m_leaf_density;
	std::vector<float> branchVertexVector;
	std::vector<unsigned int> branchIndexVector;
	std::vector<float> leafVertexVector;
	std::vector<unsigned int> leafIndexVector;
	float *branchVertexBuffer ;
	unsigned int *branchIndexBuffer;
	float *leafVertexBuffer;
	unsigned int *leafIndexBuffer;
	int addNewBranch(float radiusUp, float radiusBottom, float height, unsigned int ibindex, glm::mat4 modelToWorldMatrix);
	int addNewLeaf(float height, unsigned int ibindex, glm::mat4 modelToWorldMatrix);
	int generate(glm::vec3 globePositionUp, glm::vec3 globePositionBottom, int index, unsigned int& ibindex, unsigned int& ilindex, int& modelindex, float verticalAngle, float horizontalAngle, float height, float radiusUp, float radiusBottom, int treeHeight);
	// void countPointerNumber();
	void computeModelMatrix(glm::vec3 globePositionUp, glm::vec3 globePositionBottom, glm::mat4 &Rr3, glm::mat4 &Rr4, glm::mat4 &T);
	void computeModelMatrix2(glm::vec3 globePositionUp, glm::vec3 globePositionBottom, float va, float ha, glm::mat4 &R1, glm::mat4 &R2);
	
};