www.pudn.com > fi_treegen10.zip > graphics.cxx
//---------------------------------------------------------------------------
// graphics.cxx
// by Alex ( alex@FusionIndustries.com )
//
// 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 "graphics.h"
//---------------------------------------------------------------------------
// Procedure for creating/initializing ogl window
//---------------------------------------------------------------------------
OGL_Window::OGL_Window(int x, int y, int w, int h, const char *l)
: Fl_Gl_Window(x,y,w,h,l)
{
LEFT = -2.0; // along x
RIGHT = 2.0; // along x
BOTTOM = -2.0; // along y
TOP = 2.0; // along y
FRONT = -2.0; // along z
BACK = 2.0; // along z
NEARCLIP = 1.0f;
FARCLIP = 10.0f;
resetScene();
initialized = 0;
}
//---------------------------------------------------------------------------
OGL_Window::~OGL_Window()
{}
//---------------------------------------------------------------------------
// Called in draw (just once) because the gl window has been created by then
void OGL_Window::init()
{
if( !initialized )
{
printf( "Starting up...\n" );
glEnable(GL_TEXTURE_2D);
glEnable( GL_TEXTURE_GEN_S );
glEnable( GL_TEXTURE_GEN_T );
glTexGend( GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
glTexGend( GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
glEnable( GL_DEPTH_TEST );
glDepthFunc( GL_LESS );
glPolygonMode( GL_FRONT_AND_BACK, polymode );
srand( (unsigned)time( NULL ) ); // seed our rand tree functions
//Tree params
tree.init();
recDepth = 5;
tree.setMaxRecursionLevel( recDepth );
initialized = 1;
draw_scene();
swap_buffers();
}
}
//---------------------------------------------------------------------------
// Procedure for drawing/refreshing stuff
// -- must be named: draw ---
//---------------------------------------------------------------------------
void OGL_Window::draw()
{
// remap viewport in case it's resized
if (!valid())
{
resize( w(), h() );
init(); // only initializes on window creation
//printf( "Done\n" );
}
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
//glClearColor(0.34f, 0.50f, 0.8f, 1.0f); // rich lighter blue
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
#ifdef _DEBUG
// printf("Drawing scene...\n");
#endif
draw_scene();
swap_buffers();
#ifdef _DEBUG
// printf("Done.\n");
#endif
}
//---------------------------------------------------------------------------
// Procedure for drawing scene
//---------------------------------------------------------------------------
void OGL_Window::draw_scene()
{
glPushMatrix();
if( viewMode == ORTHOMODE )
{
glTranslated(0, 0, -(NEARCLIP+FARCLIP)/2 ); // center world at (0,0,0)
}
else if( viewMode == PROJMODE )
{
glTranslated(0, BOTTOM, -(NEARCLIP+FARCLIP)/2 ); // center world at (0,0,0)
}
glTranslatef( xpos, ypos, zpos ); // translate global coord sys
glRotatef( xrot, 1, 0, 0 ); // rotate about the global coord sys
glRotatef( yrot, 0, 1, 0 );
glRotatef( zrot, 0, 0, 1 );
glScalef( scale, scale, scale ); // scale it up!
// draw ground
//glColor3f( 0.849f, 0.534f, 0.624f ); // brown01
//glColor3f( 0.549f, 0.384f, 0.224f ); // brown02
glColor3f( 0.95f, 0.95f, 0.95f ); // grey
glBegin( GL_QUADS );
{
glVertex3f( 0.25f*LEFT, 0, 0.25f*FRONT );
glVertex3f( 0.25f*LEFT, 0, 0.25f*BACK );
glVertex3f( 0.25f*RIGHT, 0, 0.25f*BACK );
glVertex3f( 0.25f*RIGHT, 0, 0.25f*FRONT );
}
glEnd();
if( showWorldAxis )
{
drawWorldAxis();
}
tree.draw( recDepth );
glPopMatrix();
}
//---------------------------------------------------------------------------
// Procedure for handling events
// -- must be named: handle ---
//---------------------------------------------------------------------------
int OGL_Window::handle(int event)
{
static int num,x=0,y=0;
static int newx=0,newy=0;
static int buttonPressed;
switch(event)
{
case FL_PUSH:
buttonPressed = Fl::event_button();
if( buttonPressed == 1 ) // alex's trackball
{
x = Fl::event_x();
y = h()-Fl::event_y();
}
else if( buttonPressed == 2 ) // translate in xy-plane
{
x = Fl::event_x();
y = h()-Fl::event_y();
}
else if( buttonPressed == 3 ) // translate in xz-plane
{
x = Fl::event_x();
y = h()-Fl::event_y();
}
return 1;
case FL_DRAG:
//... mouse moved while down event ...
buttonPressed = Fl::event_button();
if( buttonPressed == 1 )
{
newx = Fl::event_x();
newy = h()-Fl::event_y();
// We're calculating how much to rotate the object by using the relative amount
// the mouse moved on the screen.
// If the mouse moves all the way across the screen, we perform a full rotation.
// If we only move halfway, we only do a 180 rotation, etc.
float dyRot = 360.0f*(newx - x) / w();
float dxRot = 360.0f*(newy - y) / h();
setGlobalRotationY( yrot + dyRot ); // Note to self: this is a funny way of doing it -- calling
setGlobalRotationX( xrot - dxRot ); // a member function to set a locally public var -- but
// it's less ambiguous, imo.
// set up to calc the next deltas
x = newx;
y = newy;
// finally draw the image
draw();
}
else if( buttonPressed == 2 )
{
newx = Fl::event_x();
newy = h()-Fl::event_y();
float dx = (float)(newx - x); // calc translation amt
float dy = (float)(newy - y);
dx = 4*dx / w(); // scale them down! -- we should really scale from screen coords to worldspace coords
dy = 4*dy / h();
setGlobalPosX( xpos + dx );
setGlobalPosY( ypos + dy );
// set up to calc the next deltas
x = newx;
y = newy;
// finally draw the image
draw();
}
else if( buttonPressed == 3 )
{
newx = Fl::event_x();
newy = h()-Fl::event_y();
float dx = (float)(newx - x); // calc translation amt
float dz = (float)(newy - y);
dx = 4*dx / w(); // scale them down! -- we should really scale from screen coords to worldspace coords
dz = 4*dz / h();
setGlobalPosX( xpos + dx );
setGlobalPosZ( zpos - dz );
// set up to calc the next deltas
x = newx;
y = newy;
// finally draw the image
draw();
}
return 1;
case FL_RELEASE:
//... mouse up event ...
//newx = Fl::event_x();
//newy = h()-Fl::event_y();
buttonPressed = Fl::event_button();
if( buttonPressed == 1 )
{
draw();
swap_buffers();
}
else if( buttonPressed == 2 )
{
// don't do anything
}
else if( buttonPressed == 3 )
{
// don't do anything
}
return 1;
case FL_FOCUS :
return 1;
case FL_UNFOCUS :
//... Return 1 if you want keyboard events, 0 otherwise
return 1;
case FL_KEYBOARD:
//... keypress, key is in Fl::event_key(), ascii in Fl::event_text()
//... Return 1 if you understand/use the keyboard event, 0 otherwise...
return 1;
case FL_SHORTCUT:
//... shortcut, key is in Fl::event_key(), ascii in Fl::event_text()
//... Return 1 if you understand/use the shortcut event, 0 otherwise...
return 1;
default:
// tell FLTK that I don't understand other events
return 0;
}
}
//---------------------------------------------------------------------------
// Draws a bounding box.
// (x1,y1) and (x2,y2) are opposite corners of the box
// opcode is a glLogicOp opcode (ie GL_XOR, GL_INVERT, etc);
void OGL_Window::drawBox( int x1, int y1, int x2, int y2, GLenum opcode )
{
glEnable ( GL_COLOR_LOGIC_OP );
glLogicOp( opcode );
glPushAttrib ( GL_POLYGON_BIT );
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glRectd(x1, y1, x2, y2);
glPopAttrib();
glDisable( GL_COLOR_LOGIC_OP );
}
//---------------------------------------------------------------------------
// Draws the world axis
// Note: The axis lines span the viewing volume (at least in ortho mode)
//---------------------------------------------------------------------------
void OGL_Window::drawWorldAxis()
{
glPushAttrib( GL_CURRENT_BIT ); // save the current color
glPushMatrix();
glBegin( GL_LINES );
{
// x-axis red
glColor3f ( 1.0f, 0.0f, 0.0f );
glVertex3d( LEFT, 0.0f, 0.0f );
glVertex3d( RIGHT, 0.0f, 0.0f );
// y-axis green
glColor3f ( 0.0f, 1.0f, 0.0f );
glVertex3d( 0.0f, BOTTOM, 0.0f );
glVertex3d( 0.0f, TOP, 0.0f );
// z-axis blue
glColor3f ( 0.0f, 0.0f, 1.0f );
glVertex3d( 0.0f, 0.0f, FRONT );
glVertex3d( 0.0f, 0.0f, BACK );
}
glEnd();
glPopMatrix();
glPopAttrib();
}
//---------------------------------------------------------------------------
// Resets the scene -- resets the transforms and recenters the object
//---------------------------------------------------------------------------
void OGL_Window::resetScene()
{
showWorldAxis = false;
polymode = GL_FILL;
viewMode = PROJMODE;
// Global transforms
xrot = yrot = zrot = 0.0f;
xpos = ypos = zpos = 0.0f;
scale = 1.0f;
recDepth = 5;
tree.setMaxRecursionLevel( recDepth );
tree.setPrimitiveType ( CYLINDER );
tree.setLevelOfDetail ( 0.5f );
tree.setBranchesPerLevel ( 2 );
tree.setTwist ( 180 );
tree.setSpread ( 25 );
tree.useLeaves ( false );
tree.setUseDisplayList( false );
//tree.setTreeBase( 0 ); // don't reset the tree base
glEnable( GL_TEXTURE_2D );
glEnable( GL_TEXTURE_GEN_S );
glEnable( GL_TEXTURE_GEN_T );
glTexGend( GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
glTexGend( GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
glPolygonMode( GL_FRONT_AND_BACK, polymode );
valid( 0 ); // force a redraw, including updating the projection mode
}
//---------------------------------------------------------------------------
void OGL_Window::resize( GLsizei w, GLsizei h )
{
if( h == 0 ) h = 1; // prevent div by 0
glViewport( 0,0,w,h );
// reset coord sys
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
if( viewMode == ORTHOMODE )
{
glOrtho( LEFT, RIGHT,
0, (TOP-BOTTOM)*h/w, // makes a 1:1 viewing ratio
NEARCLIP, FARCLIP );
}
else if( viewMode == PROJMODE )
{
GLfloat aspect = (GLfloat)w/(GLfloat)h;
gluPerspective( 60.0f, aspect, 1.0f, 600.0f );
}
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
}
//---------------------------------------------------------------------------
// Function to quit application
//---------------------------------------------------------------------------
void OGL_Window::quit()
{
if( fl_ask( "Are you sure you want to quit?" ) )
{
exit(0);
}
}
//-- E O F ------------------------------------------------------------------