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 ------------------------------------------------------------------