www.pudn.com > fi_treegen10.zip > Tree.cpp
//---------------------------------------------------------------------------
// Tree.cpp
// by Alex ( alex@FusionIndustries.com )
// Created May 14, 2001
//
// This code may be freely used in any project, as long as credit
// or greetz are given. Please also let me know if you use this
// code, find it useful, or even if you don't like it.
//---------------------------------------------------------------------------
#include "Tree.h"
//---------------------------------------------------------------------------
Tree::Tree()
{
initialized = 0;
texId = 0;
maxRecursionLevel = 8;
branchesPerLevel = 2;
currPrim = PLANE;
quadric = gluNewQuadric();
useLeaves( false );
line[0] = 0;
line[1] = 1.0f;
line[2] = 0.0f;
currLOD = 0.5f;
spread = 45;
twist = 0;
treeBaseType = 0;
currColorScheme = false;
useDisplayList = false;
displayListId = 1; // these are only used if the display list code is enabled
treeGeomValid = false;
}
//---------------------------------------------------------------------------
void Tree::init()
{
if( initialized == 0 )
{
texId = 0;
maxRecursionLevel = 10;
texId = pngBind( "treeTex.png", PNG_NOMIPMAP, PNG_SOLID, NULL,
GL_REPEAT, GL_NEAREST, GL_NEAREST );
if( texId == 0)
{
printf( "Couldn't find tree texture (treeTex.png)!\n" );
printf( "Make sure it is in the same directory as the executable and run again.\n" );
printf( "Quitting\n" );
exit(0);
}
initialized = 1;
}
}
//---------------------------------------------------------------------------
void Tree::shutdown()
{
if( initialized )
{
if( glIsList(displayListId) == GL_TRUE )
{
glDeleteLists( displayListId, 1 );
}
glDeleteTextures( 1, &texId );
texId = 0;
initialized = 0;
}
}
//---------------------------------------------------------------------------
// Wrapper for the recursive draw function.
// Putting the display list building code here makes things easy, because
// we don't have to worry about what level of recursion we're on to decide
// whether to start or stop building the display list
//---------------------------------------------------------------------------
// Tradeoffs with the display list: when enabled, it takes longer to see
// any changes that you make to the tree, but rotating and moving the
// tree around goes much faster. When not using display lists, changes are
// shown instantly, but it can take longer to display.
void Tree::draw( unsigned int currLevel )
{
if( glIsEnabled(GL_TEXTURE_2D) )
{
glBindTexture( GL_TEXTURE_2D, texId );
}
// HACK ALERT!
// Turn off depth testing when we're using planes and only have 2 branches
// This is mainly used as a demo mode to show how it works
if( currPrim == PLANE && branchesPerLevel == 2)
{
glDisable( GL_DEPTH_TEST );
}
else
{
glEnable( GL_DEPTH_TEST );
}
// Draw method is selected here
if( !useDisplayList )
{
drawRecTree(currLevel);
}
else if( treeGeomValid && useDisplayList) // just display the compiled tree
{
if( glIsList(displayListId) == GL_TRUE )
{
//printf( "Drawing compiled tree...\n" );
glCallList( displayListId );
}
else
{
printf( "Tree::draw() error: invalid list (%d)\n", displayListId );
}
}
else // build a new tree
{
printf( "Building a new tree..." );
glDeleteLists( displayListId, 1 ); // delete our only list
glNewList( displayListId, GL_COMPILE_AND_EXECUTE );
drawRecTree(currLevel);
glEndList();
printf( "done\n" );
treeGeomValid = true;
}
}
//---------------------------------------------------------------------------
// Func: void drawRecTree( unsigned int currLevel )
// Desc: Recursively draws a textured tree. Recurses currLevel levels deep
// Parm: currLevel: the bigger the number, the more times it will recurse.
// It stops when currLevel == 0
//---------------------------------------------------------------------------
void Tree::drawRecTree( unsigned int currLevel )
{
if( currLevel > 0 )
{
// scale->0 as we recurse deeper and deeper
float scale = (float)currLevel / (float)maxRecursionLevel;
// we can do this because 0 <= scale <= 1
if( currColorScheme )
{
glColor3f(1 * scale, 1-scale, 0); // red to green
}
else
{
glColor3f(0.7f*scale, 0.4f+0.2f*scale,0.4f*scale); // tree colors
}
switch( currPrim )
{
case LINE:
drawLinePrim( scale );
break;
case PLANE:
drawPlanePrim( scale );
break;
case CYLINDER:
{
// the second scale becomes the first scale in the next iter
// and the pieces fit very snugly
float scaleNext = (currLevel-1) / (float)maxRecursionLevel;
drawCylinderPrim( scale, scaleNext );
}
break;
case SPHERE:
drawSpherePrim( scale );
break;
default:
printf( "Error: unknown shape. Defaulting to plane\n" );
currPrim = PLANE;
break;
}
if( drawLeaves )
{
if( currLevel <= 2 )
{
glPushMatrix();
glTranslatef( 0, scale, 0 );
glRotatef( (GLfloat)(rand()%60), 0, 0, 1 ); // makes the leaves "flutter in the wind"
glRotatef( (GLfloat)(rand()%60), 0, 1, 0 ); // we should really be saving these vals
glRotatef( (GLfloat)(rand()%60), 1, 0, 0 ); // or finding a seed that will generate the
drawPlanePrim( 0.5f * scale ); // same params each time the tree is moved
glPopMatrix();
}
}
glPushMatrix();
{
float dTheta = 360.0f / (float)branchesPerLevel;
float rot = 24.0f;
// We're currently in the default position,
// which is parallel to the y-axis (straight up)
// The following transforms are relative to any previous transforms;
// they are not absolute transforms.
// Ahhh... the beauty of the transformation matrix stack.
for( unsigned int i = 0; i < branchesPerLevel; i++ )
{
glPushMatrix();
if( treeBaseType == 0 ) // Base: all branches per level start at the same point
{
// move to the end of the primitive
glTranslatef( scale * line[0], scale * line[1], 0 );
}
else if( treeBaseType > 0 ) // Base: each branch spirals up
{
// move to the end of the primitive
glTranslatef( scale * line[0], scale * line[1] * float(i+1) / float(branchesPerLevel), 0 );
}
glRotatef( (GLfloat)i*dTheta, 0, 1, 0 ); // distributes the branches around the previous branch
glRotatef( (GLfloat)twist, 0, 1, 0 ); // how much more to rotate each branch
glRotatef( (GLfloat)spread, 0, 0, 1 ); // how much to rotate branch away from the y-axis/up
drawRecTree( currLevel - 1 ); // recursively draw the rest of the branches that are connected to this one
glPopMatrix();
}
}
glPopMatrix();
}
}
//---------------------------------------------------------------------------
// Desc: draws a line
// Parm: float scale: typically ranges between 0 and 1 but can be anything
//---------------------------------------------------------------------------
void Tree::drawLinePrim( float scale )
{
glBegin( GL_LINES );
{
glVertex3f( 0, 0, 0 );
glVertex3f( scale * line[0], scale * line[1], 0 );
}
glEnd();
}
//---------------------------------------------------------------------------
// Parm: float scale: typically ranges between 0 and 1 but can be anything
//---------------------------------------------------------------------------
void Tree::drawPlanePrim( float scale )
{
glBegin( GL_QUADS );
{
// draw a quad slightly longer than the line-segment
float width = scale * 0.8f;
float height = scale * (line[1] * 1.5f);
glTexCoord2f( 0.0f, 1.0f ); // upper-left
glVertex2f ( -width/2, 0.0f );
glTexCoord2f( 0.0f, 0.0f ); // lower-left
glVertex2f ( -width/2, height );
glTexCoord2f( 1.0f, 0.0f ); // lower-right
glVertex2f ( width/2, height );
glTexCoord2f( 1.0f, 1.0f ); // upper-right
glVertex2f ( width/2, 0.0f );
}
glEnd();
}
//---------------------------------------------------------------------------
// Parm: float scaleBase, scaleTop: typically ranges between 0 and 1
// but can be anything
//---------------------------------------------------------------------------
void Tree::drawCylinderPrim( float scaleBase, float scaleTop )
{
glPushMatrix();
glRotatef( -90.0f, 1,0,0);
gluCylinder( quadric, // bottom radius, top radius, height, slices, stacks
0.25f * scaleBase,
0.25f * scaleTop,
scaleBase * line[1],
int(currLOD*16),
int(currLOD*4) );
glPopMatrix();
}
//---------------------------------------------------------------------------
// Parm: float scale: typically ranges between 0 and 1 but can be anything
//---------------------------------------------------------------------------
void Tree::drawSpherePrim( float scale )
{
glPushMatrix();
glRotatef( -90.0f, 1, 0, 0 );
gluSphere( quadric, scale*0.6f, int(currLOD*20), int(currLOD*16) );
glPopMatrix();
}
//-- E O F ------------------------------------------------------------------