On 02/08/12 09:50, Greg Ercolano wrote:
>> Well, I guess the original code is in the public domain, so I imagine
>> that'd be OK, though my "additions" might need a little tidying up as
>> they might not be exhibiting the best fltk-way to do the things I
>> added...
> 
>       I'll take a stab at a cleanup.
>       I /think/ I can take out all the glut stuff and make it use
>       Fl::run().

   Done; see below.

   Took out all the glut; pure FLTK app now.
   Uses Fl::run(), handle() for key events, etc.
   Possibly rushed; have to get back to work.. some eyes to check it
   would be good. Could probably use more attention to removing globals.

   Tested on linux (Cenos5.6), OSX (SnowLep), and Windows (w/2005 express).

   I get 99fps on linux + osx (both running on similar Mac Mini hardware)
   and around 64fps on windows running on an old 2GHz AMD64 box with
   probably crappy onboard graphics.

   Made it more or less conforming to the CMP.
   With FLTK headers/footers, it'd probably be ready for svn.

   +1 to add it to FLTK test directory.

-----------------------------------------------------------------------

//
// 3-D gear wheels.  This program is in the public domain.
//
// Command line options:
//    -info      print GL implementation information
//    -exit      automatically exit after 30 seconds
//
//
// Brian Paul
//

// Conversion to GLUT by Mark J. Kilgard
// Conversion to FLTK by IMM + Greg Ercolano
// Compile as:  fltk-config --use-gl --compile fl_gears.cxx
//

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Gl_Window.H>
#include <FL/Fl_Output.H>
#include <FL/Fl_Box.H>
#include <FL/gl.h>

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

static int autoexit = 0;
static int infoflag = 0;
static float desired_frame_rate = 100.0;
static float per_frame_time = 1.0 / desired_frame_rate;

static const float pos[4]   = { 5.0, 5.0, 10.0, 0.0 };
static const float red[4]   = { 0.8, 0.1, 0.0, 1.0  };
static const float green[4] = { 0.0, 0.8, 0.2, 1.0  };
static const float blue[4]  = { 0.2, 0.2, 1.0, 1.0  };

Fl_Output *fps_out=0, *fps_max=0, *fps_avg=0;

class MyGlWindow : public Fl_Gl_Window {
  int gear1, gear2, gear3, frames, timerstate;
  time_t last_tod;
  float f_max, f_avg;
  float view_rotx, view_roty, view_rotz, angle;
  // Handle fixed FPS rate timer
  static void FixedFPS(void *userdata) {
    MyGlWindow *glwin = (MyGlWindow*)userdata;
    Fl::repeat_timeout(per_frame_time, FixedFPS, userdata);
    static short fixed_angle = 0;
    fixed_angle += 500;
    glwin->angle = (double)(fixed_angle) * 180.0 / 32768.0;
    glwin->redraw();
  }
  // Handle FPS metering timer
  static void MeasureFPS(void *userdata) {
    MyGlWindow *glwin = (MyGlWindow*)userdata;
    time_t new_tod = time(NULL);
    time_t delta_tod = new_tod - glwin->last_tod;
    float fps = glwin->frames / (float)delta_tod;
    // Show rate info on console
    printf("%d frames in %d seconds = %6.3f FPS\n", glwin->frames, delta_tod, 
fps);
    fflush(stdout);
    // Update fps meters
    {
      char s[80];
      if (fps > glwin->f_max) {
        glwin->f_max = fps;
        sprintf(s, "%.2f", glwin->f_max); fps_max->value(s);
      }
      if (glwin->f_avg == 0 ) {
        glwin->f_avg = fps;
      } else {
        glwin->f_avg = (glwin->f_avg * 0.7) + (fps * 0.3);
      }
      glwin->last_tod = new_tod;
      sprintf(s, "%.2f", glwin->f_avg); fps_avg->value(s);
      sprintf(s, "%.2f", fps);          fps_out->value(s);
    }
    // Auto exit?
    if (autoexit) {
      autoexit = autoexit - (int)delta_tod;
      if (autoexit <= 0) exit(0);
    }
    glwin->frames = 0;  // rezero frame counter
    Fl::repeat_timeout(5.0, MeasureFPS, userdata);
  }

  // Start/Stop timers
  void Timers(int newstate) {
    // Timer state changing?
    if ( newstate == timerstate ) return;
    if ( newstate ) {
      // Enable timers?
      Fl::add_timeout(5.0,            MeasureFPS, (void*)this);    // compute 
FPS every 5 secs
      Fl::add_timeout(per_frame_time, FixedFPS,   (void*)this);    // draw at 
desired FPS
      frames = 0;
      f_max  = 0.0;
      f_avg  = 0.0;
      last_tod = time(NULL);
    } else {
      // Disable timers?
      Fl::remove_timeout(FixedFPS,   (void*)this);
      Fl::remove_timeout(MeasureFPS, (void*)this);
    }
    timerstate = newstate;
  }
public:
  // CTOR
  MyGlWindow(int X,int Y,int W,int H,const char*L=0) : Fl_Gl_Window(X,Y,W,H,L) {
    // Init vars
    frames     = 0;
    f_max      = 0.0;
    f_avg      = 0.0;
    last_tod   = 0;
    timerstate = 0;
    view_rotx  = 20.0;
    view_roty  = 30.0;
    view_rotz  = 0.0;
    angle      = 0.0;
    // Start fps timers
    Timers(1);
  }

private:
  // Draw a gear wheel.  You'll probably want to call this function when
  // building a display list since we do a lot of trig here.
  //
  //     Input:  inner_radius - radius of hole at center
  //        outer_radius - radius at center of teeth
  //        width - width of gear
  //        teeth - number of teeth
  //        tooth_depth - depth of tooth
  //
  void gear(float inner_radius,
            float outer_radius,
            float width,
            int teeth, float tooth_depth) {
    int i;
    float r0 = inner_radius;
    float r1 = outer_radius - tooth_depth / 2.0;
    float r2 = outer_radius + tooth_depth / 2.0;
    float da = 2.0 * M_PI / teeth / 4.0;
    // draw front face
    glShadeModel(GL_FLAT);
    glNormal3f(0.0, 0.0, 1.0);
    glBegin(GL_QUAD_STRIP);
    for (i = 0; i <= teeth; i++) {
      float angle = i * 2.0 * M_PI / teeth;
      glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
      glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
      if (i < teeth) {
        glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
        glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 
0.5);
      }
    }
    glEnd();
    // draw front sides of teeth
    glBegin(GL_QUADS);
      da = 2.0 * M_PI / teeth / 4.0;
      for (i = 0; i < teeth; i++) {
        float angle = i * 2.0 * M_PI / teeth;
        glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
        glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
        glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 
0.5);
        glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 
0.5);
      }
    glEnd();
    // draw back face
    glNormal3f(0.0, 0.0, -1.0);
    glBegin(GL_QUAD_STRIP);
      for (i = 0; i <= teeth; i++) {
        float angle = i * 2.0 * M_PI / teeth;
        glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
        glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
        if (i < teeth) {
          glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width 
* 0.5);
          glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
        }
      }
    glEnd();
    // draw back sides of teeth
    glBegin(GL_QUADS);
      da = 2.0 * M_PI / teeth / 4.0;
      for (i = 0; i < teeth; i++) {
        float angle = i * 2.0 * M_PI / teeth;
        glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 
0.5);
        glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 
0.5);
        glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
        glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
      }
    glEnd();
    // draw outward faces of teeth
    glBegin(GL_QUAD_STRIP);
      for (i = 0; i < teeth; i++) {
        float angle = i * 2.0 * M_PI / teeth;
        glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
        glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
        float u = r2 * cos(angle + da) - r1 * cos(angle);
        float v = r2 * sin(angle + da) - r1 * sin(angle);
        float len = sqrt(u * u + v * v);
        u /= len;
        v /= len;
        glNormal3f(v, -u, 0.0);
        glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
        glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
        glNormal3f(cos(angle), sin(angle), 0.0);
        glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 
0.5);
        glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 
0.5);
        u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
        v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
        glNormal3f(v, -u, 0.0);
        glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 
0.5);
        glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 
0.5);
        glNormal3f(cos(angle), sin(angle), 0.0);
      }
      glVertex3f(r1 * cos(0.0), r1 * sin(0.0), width * 0.5);
      glVertex3f(r1 * cos(0.0), r1 * sin(0.0), -width * 0.5);
    glEnd();
    // draw inside radius cylinder
    glShadeModel(GL_SMOOTH);
    glBegin(GL_QUAD_STRIP);
    for (i = 0; i <= teeth; i++) {
      float angle = i * 2.0 * M_PI / teeth;
      glNormal3f(-cos(angle), -sin(angle), 0.0);
      glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
      glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
    }
    glEnd();
  }
  void draw() {
    // First time? init viewport, etc.
    if (!valid()) {
      valid(1);
      glEnable(GL_DEPTH_TEST);
      glClearColor(0.0, 0.0, 0.4, 0.0);
      {
        GLfloat H = (float)h() / (float)w();
        glViewport(0, 0, w(), h());
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glFrustum(-1.0, 1.0, -H, H, 5.0, 60.0);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0.0, 0.0, -40.0);
      }
      glLightfv(GL_LIGHT0, GL_POSITION, pos);
      glEnable(GL_CULL_FACE);
      glEnable(GL_LIGHTING);
      glEnable(GL_LIGHT0);
      glEnable(GL_DEPTH_TEST);
      static int init = 0;
      if ( ! init ) {
        init = 1;
        // make gear1
        gear1 = glGenLists(1);
        glNewList(gear1, GL_COMPILE);
        glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
        gear(1.0, 4.0, 1.0, 20, 0.7);
        glEndList();
        // make gear2
        gear2 = glGenLists(1);
        glNewList(gear2, GL_COMPILE);
        glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
        gear(0.5, 2.0, 2.0, 10, 0.7);
        glEndList();
        // make gear3
        gear3 = glGenLists(1);
        glNewList(gear3, GL_COMPILE);
        glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
        gear(1.3, 2.0, 0.5, 10, 0.7);
        glEndList();
        // post init
        glEnable(GL_NORMALIZE);
      }
      if ( infoflag ) {
        printf("GL_RENDERER   = %s\n", (char *)glGetString(GL_RENDERER));
        printf("GL_VERSION    = %s\n", (char *)glGetString(GL_VERSION));
        printf("GL_VENDOR     = %s\n", (char *)glGetString(GL_VENDOR));
        printf("GL_EXTENSIONS = %s\n", (char *)glGetString(GL_EXTENSIONS));
        fflush(stdout);
      }
    }
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // Draw the gears in current viewing position
    glPushMatrix();
      glRotatef(view_rotx, 1.0, 0.0, 0.0);
      glRotatef(view_roty, 0.0, 1.0, 0.0);
      glRotatef(view_rotz, 0.0, 0.0, 1.0);
      // Draw gear#1
      glPushMatrix();
        glTranslatef(-3.0, -2.0, 0.0);
        glRotatef(angle, 0.0, 0.0, 1.0);
        glCallList(gear1);
      glPopMatrix();
      // Draw gear#2
      glPushMatrix();
        glTranslatef(3.1, -2.0, 0.0);
        glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
        glCallList(gear2);
      glPopMatrix();
      // Draw gear#3
      glPushMatrix();
        glTranslatef(-3.1, 4.2, 0.0);
        glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
        glCallList(gear3);
      glPopMatrix();
    glPopMatrix();
    frames++;           // count the redraws
  }
public:
  // Fltk event handler
  int handle(int e) {
    int ret = 0;
    switch (e) {
      case FL_HIDE:  Timers(0); break;
      case FL_SHOW:  Timers(1); break;
      case FL_ENTER: ret = 1;   break;
      case FL_LEAVE: ret = 1;   break;
      case FL_FOCUS: ret = 1;   break;
      case FL_KEYBOARD:
        // Keyboard keys
        switch ( Fl::event_key() ) {
          case FL_Up:    view_rotx -= 5.0; ret = 1; break;
          case FL_Down:  view_rotx += 5.0; ret = 1; break;
          case FL_Left:  view_roty -= 5.0; ret = 1; break;
          case FL_Right: view_roty += 5.0; ret = 1; break;
          case 'z':
            if (Fl::event_state() & FL_SHIFT) view_rotz -= 5.0;
            else view_rotz += 5.0;
            ret = 1;
            break;
        }
        break;
    }
    ret |= Fl_Gl_Window::handle(e);
    return(ret);
  }
};

int main(int argc, char *argv[]) {
  Fl_Window window(320, 410, "Gears");
  window.begin();
    MyGlWindow glwin(10,10,300,300);
    // Create output displays for various fps metering
    fps_out = new Fl_Output( 60, 318+0,  140, 25, "FPS:");
    fps_out->value("Calculating..");
    fps_out->clear_visible_focus();
    fps_max = new Fl_Output( 60, 318+30, 140, 25, "MAX:");
    fps_max->value("Calculating..");
    fps_max->clear_visible_focus();
    fps_avg = new Fl_Output( 60, 318+60, 140, 25, "AVG:");
    fps_avg->value("Calculating..");
    fps_avg->clear_visible_focus();
    // Legend
    Fl_Box box(210,318,100,85,"Keys:\n  Up/Dn\n  Lt/Rt\n  z/Z/Esc");
    box.align(FL_ALIGN_INSIDE | FL_ALIGN_TOP | FL_ALIGN_LEFT);
    box.box(FL_BORDER_BOX);
  window.end();
  window.resizable(window);
  window.show();
  // Command line args
  for ( int i=1; i<argc; i++ ) {
    if (strcmp(argv[i], "-info")==0) { infoflag = 1; }
    else if (strcmp(argv[i], "-exit")==0) {
      autoexit = 35;
      printf("Auto Exit after approx. %i seconds.\n", autoexit);
      fflush(stdout);
    }
  }
  return(Fl::run());
}
// End of File
_______________________________________________
fltk mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk

Reply via email to