#include <stdlib.h>
#include <time.h>
#include <GL/glut.h>
using namespace std;

GLuint makeaTree;
float x, y, z, gcolor = 0.16;//绿色值

//画树枝（树干）
void makeCylinder(float height, float base){//高度，底面半径
	GLUquadric *obj = gluNewQuadric();//创建一个二次曲面
	gcolor += 0.0006;
	glColor3f(0.64f, gcolor, 0.16f); //设置颜色
	glPushMatrix();//入栈，消除上一次变换对下一次变换的影响
	glRotatef(-90, 1.0, 0.0, 0.0);//顺时针旋转90度，绕x轴
	//生成一个圆台，底面半径base,顶部半径比底面半径小0.2倍，高度，环绕Z轴细分次数，沿着z轴细分次数
	gluCylinder(obj, base, base - (0.2*base), height, 20, 10);
	glPopMatrix();//出栈，消除上一次变换对下一次变换的影响
	glutSwapBuffers();
}

void makeTree(float height, float base){

	float angle, xx,yy,zz;//旋转角度和旋转轴
	makeCylinder(height, base); 
	glTranslatef(0.0, height, 0.0);//平移到树枝顶端
	height -= height*.2; base -= base*0.3;//新的分枝比上一级树枝短0.2倍，细0.3倍
	for (int a = 0; a<3; a++){//每个树枝新生成3个分枝
		{
			switch (a)//三个分枝分别向不同的方向生长
			{
			case 0:xx = 1, yy = 0, zz = 0; break;
			case 1:xx = 1, yy = 1, zz = -1; break;
			case 2:xx = 0, yy = 0, zz = 1; break;
			default:
				break;
			}
		}
		angle = rand() % 50 + 20;//生成一个合适的旋转角度
		if (angle >48)
			angle = -(rand() % 50 + 20);
		if (height >1){//递归生成新的树枝，直到树枝的高度小于1
			glPushMatrix();
			glRotatef(angle, xx, yy, zz);//旋转
			makeTree(height, base);//递归调用
			glPopMatrix();
		}
		else {//最后一层树枝的末端
			glColor3f(0.4, 1-gcolor, 0.3);//设置果实或树叶的颜色，绿色值不同区分不同的实体
			glutSolidSphere(.2, 10, 10);// 生成树叶和果实
		}
	}
}
void init(void)
{

	glClearColor(1.0, 1.0, 1.0, 1.0);
	glShadeModel(GL_SMOOTH);
	glEnable(GL_DEPTH_TEST);
	makeaTree = glGenLists(1);//创建一个显示列表
//	srand((unsigned)time(NULL));//生成随机数
	glNewList(makeaTree, GL_COMPILE);
	makeTree(4.2, 0.2);//树干的高度4.2，底部半径0.2
	glEndList();
}
void keyboard(unsigned char key, int xx, int yy){//设置键盘按键响应
	switch (key){
	case 'x'://按下x键绕x轴旋转
		x += 10;
		glutPostRedisplay();
		break;
	case 'y'://按下y键绕y轴旋转
		y += 10;
		glutPostRedisplay();
		break;
	case 'z'://按下z键绕z轴旋转
		z += 10;
		glutPostRedisplay();
		break;
	}
}

void display(){
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glPushMatrix();
	glRotatef(x, 1.0, 0.0, 0.0);//对键盘按键的响应
	glRotatef(y, 0.0, 1.0, 0.0);
	glRotatef(z, 0.0, 0.0, 1.0);
	glCallList(makeaTree);//执行显示列表

	glPopMatrix();
	glutSwapBuffers();
}
void reshape(int w, int h)
{
	glViewport(0, 0, (GLsizei)w, (GLsizei)h);
	glMatrixMode(GL_PROJECTION);//指定当前操作投影矩阵堆栈
	glLoadIdentity(); //重置矩阵函数，将之前的变换消除
	//指定观察的视景体在世界坐标系中的具体大小，视角22度，宽高比计算得出，裁面近处和远处的z坐标
	gluPerspective(22.0, (GLfloat)w / (GLfloat)h, 0.001, 1000.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0, 6, 50, 0, 7, 00.0, 0, 1.0, 0);//设置视点
}
void main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);//设置窗口初始显示模式
	glutInitWindowSize(800, 730);//设置窗口大小
	glutInitWindowPosition(0, 0);//设置窗口位置
	glutCreateWindow("一棵树");
	init();
	glutReshapeFunc(reshape);
	glutKeyboardFunc(keyboard);
	glutDisplayFunc(display);
	glutMainLoop();
}