
/* this class (prettytrees) uses L-systems to generate some decent trees. */

PrettyTrees::PrettyTrees()
{
	 (.1f,.9f,.1f);
	listInitd = false;
	int numIters = 4;
	strToDraw = lSys(numIters);
}

//call this once to get all the vertex data, so we don't have to recompute it all every single frame update
//then throw all that data into a displaylist
void PrettyTrees::initList()
{
	theTree = glGenLists(1);

	glNewList(theTree,GL_COMPILE);
		drawString();
	glEndList();

	//we're done using the string, so free it!
	free(strToDraw);
	
}

//Main draw method. Draws the four branches so we get something resembling a tree
void PrettyTrees::draw(DrawingState*)
{
	if(!listInitd)
	{
		initList();
		listInitd = true;
	}
	glPushMatrix();
		glNormal3f(0.0f,0.0f,1.0f);
		glPushMatrix();
			glCallList(theTree);
		glPopMatrix();

		glPushMatrix();
			glRotatef(90,0.0f,1.0f,0.0f);
			glCallList(theTree);
		glPopMatrix();

		glPushMatrix();
			glRotatef(180,0.0f,1.0f,0.0f);
			glCallList(theTree);
		glPopMatrix();

		glPushMatrix();
			glRotatef(270,0.0f,1.0f,0.0f);
			glCallList(theTree);
		glPopMatrix();	
	glPopMatrix();
}

//computes all the vertices data based on the string strToDraw.
/* (thanks wikipedia)
    variables: X F
	constants: + -
	start: X
	rules (x -> F - [ [X] + X] + F [+FX] - X ), (F -> FF)
	angle: 25 degrees

	F means draw forward
	- means rotate left 25 deg
	+ means rotate right 25 deg
	X controls the evolution of the curve
	[ saves current position and angle and these are restored on a ]
	-> means "turns in to"
*/

void PrettyTrees::drawString()
{
	int lenS = static_cast<int>(strlen(strToDraw));

	for(int i = 0; i < lenS; i++)
	{
		if(strToDraw[i] == 'F')
		{
			//draw forward
			glTranslated(0.0,0.35,0.0);
			//i++;
			if(i < 8)
				glColor3f(0.5f,0.5f,0.25f);
			else
			{
				glColor3f(0.0f,1.0f,0.0f);

			}

			drawLeaf();
			continue;
		}
		if(strToDraw[i] == '-')
		{
			//left is positive...how strange.
			glRotatef(25.0f, 0.0f, 0.0f,1.0f);
			//i++;
			continue;
		}
		if(strToDraw[i] == '+')
		{
			glRotatef(-25.0f,0.0f,0.0f,1.0f);
			continue;
		}
		if(strToDraw[i] == '[')
		{
			glPushMatrix();
			continue;
		}
		if(strToDraw[i] == ']')
		{
			glPopMatrix();
			continue;
		}
	}
}

//starts the recursive calls
char* PrettyTrees::lSys(int iters)
{
	//using std::string slows the whole thing down too much
	char* s = (char*)calloc(fourItrs,sizeof(char));

	//initial value
	strcpy(s, "X");
	return lSysHelper(0,iters,s);;
}

char* PrettyTrees::lSysHelper(int terminate, int iters, char* str)
{
	if(terminate == iters)
		return str;

	int newInd = 0;
	char* tmp = (char*)calloc(fourItrs,sizeof(char));
	
	int lenS = static_cast<int>(strlen(str));

	for(int i = 0; i < lenS; i++)
	{
		//if the curr char in the str is an X,
		// turn it into a big long string.
		if(str[i] == 'X')
		{
			strcat(tmp, "F-[[X]+X]+F[+FX]-X");
			newInd += 18;
			continue;
		}
		//if the current character in the string is an F,
		//	we need to turn it into a FF
		if(str[i] == 'F')
		{
			strcat(tmp, "FF");
			newInd += 2;
			continue;
		}
		//set the current character in str to
		// the 'same' position in tmp, taking into account
		// the huge jumps from when we read X or F
		tmp[newInd] = str[i];
		newInd++;
	}
	free(str);
	return lSysHelper(terminate+1, iters, tmp);
}

void PrettyTrees::drawLeaf()
{
	float depthOfLeaf = -0.125f;
	float halfHeight = 0.25f;
	float halfWidth = 0.5f;

	glBegin(GL_TRIANGLES);	
		//front of the triangle
		glVertex3f(-halfWidth,-halfHeight,0.0f);
		glVertex3f(halfWidth,-halfHeight,0.0f);
		glVertex3f(0.0f,halfHeight,0.0f);
		//back of the triangle
		glVertex3f(halfWidth,-halfHeight,depthOfLeaf);
		glVertex3f(-halfWidth,-halfHeight,depthOfLeaf);
		glVertex3f(0.0f,halfHeight,depthOfLeaf);
	glEnd();

	// the next 3 fill the gaps between the triangles
	glBegin(GL_QUADS);
		glVertex3f(0.0f,halfHeight, depthOfLeaf);
		glVertex3f(-halfWidth, -halfHeight, depthOfLeaf);
		glVertex3f(-halfWidth,-halfHeight,0.0f);
		glVertex3f(0.0f,halfHeight,0.0f);
	glEnd();

	glBegin(GL_QUADS);
		glVertex3f(0.0f,halfHeight,0.0f);
		glVertex3f(halfWidth,-halfHeight,0.0f);
		glVertex3f(halfWidth,-halfHeight,depthOfLeaf);
		glVertex3f(0.0f,halfHeight,depthOfLeaf);
	glEnd();

	glBegin(GL_QUADS);
		glVertex3f(-halfWidth,-halfHeight,depthOfLeaf);
		glVertex3f(halfWidth,-halfHeight,depthOfLeaf);
		glVertex3f(halfWidth,-halfHeight,0.0f);
		glVertex3f(-halfWidth,-halfHeight,0.0f);
	glEnd();
}
