> Ian, I tried to compile your prog in MinGW with gcc 4.6.1 > and sadly it doesn't compile. > The following is the output.. > > $ fltk-config --use-gl --compile fl_gears.cxx > g++ -I/usr/local/include -I/usr/local/include/FL/images -mwindows - > DWIN32 -DUSE_OPENGL32 > -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -o 'fl_gears' > 'fl_gears.cxx' -mwindows /usr/local/lib/libfltk_gl.a -lglu32 -lopengl32 > /usr/local/lib/libfltk.a -lole32 -luuid -lcomctl32 > fl_gears.cxx: In function 'void cb_set_idle(Fl_Check_Button*, void*)': > fl_gears.cxx:66:15: error: 'static void MyGlWindow::FixedFPS(void*)' is > private > fl_gears.cxx:385:31: error: within this context > fl_gears.cxx:58:15: error: 'static void MyGlWindow::IdleFPS(void*)' is > private > fl_gears.cxx:386:25: error: within this context > fl_gears.cxx:58:15: error: 'static void MyGlWindow::IdleFPS(void*)' is > private > fl_gears.cxx:390:28: error: within this context > fl_gears.cxx:66:15: error: 'static void MyGlWindow::FixedFPS(void*)' is > private > fl_gears.cxx:391:43: error: within this context > > > My C++ isn't what it should be and I've failed to fix it. > Either that or I'm just too tired (yaaaaaaawnnnn)
Yup - I got this too, when testing on OSX. The problem is that the IdleFPS and FixedFPS methods now need to be public methods of the MyGlWindow class, so that my callback for attaching and detaching them (via the set_idle checkbutton) can access them. For some reason, the (older) gcc-3.4.something I was using didn't mind (though I think it should have) and the code worked. A "happier" version might look more like this: ------------------------------------ // // 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_Group.H> #include <FL/Fl_Window.H> #include <FL/Fl_Gl_Window.H> #include <FL/Fl_Output.H> #include <FL/Fl_Spinner.H> #include <FL/Fl_Check_Button.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 }; static Fl_Output *fps_out=NULL, *fps_max=NULL, *fps_avg=NULL; static Fl_Spinner *set_fps=NULL; static Fl_Check_Button *set_idle=NULL; 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 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, (int)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; int do_idle = 0; if(set_idle) do_idle = set_idle->value(); if ( newstate ) { // Enable timers? Fl::add_timeout(5.0, MeasureFPS, (void*)this); // compute FPS every 5 secs if(do_idle) { Fl::add_idle(IdleFPS, (void*)this); // draw as fast as possible } else { 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(MeasureFPS, (void*)this); if(do_idle) { Fl::remove_idle(IdleFPS, (void*)this); } else { Fl::remove_timeout(FixedFPS,(void*)this); } } timerstate = newstate; } public: // Handle the redrawing of the scene (from the idle loop) static void IdleFPS(void *userdata) { MyGlWindow *glwin = (MyGlWindow*)userdata; static short fixed_angle = 0; fixed_angle += 500; glwin->angle = (double)(fixed_angle) * 180.0 / 32768.0; glwin->redraw(); } // 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(); } // 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); } }; // FPS target setting callback static void cb_set_fps(Fl_Spinner*, void*) { desired_frame_rate = set_fps->value(); per_frame_time = 1.0 / desired_frame_rate; } // cb_set_fps // set idle button callback static void cb_set_idle(Fl_Check_Button*, void *v) { MyGlWindow *glwin = (MyGlWindow *)v; int do_idle = set_idle->value(); if(do_idle) { set_fps->deactivate(); Fl::remove_timeout(glwin->FixedFPS,glwin); Fl::add_idle(glwin->IdleFPS,glwin); } else { set_fps->activate(); Fl::remove_idle(glwin->IdleFPS,glwin); Fl::add_timeout(per_frame_time,glwin->FixedFPS,glwin); } } // cb_set_idle int main(int argc, char *argv[]) { Fl_Window window(320, 440, "Gears"); window.begin(); MyGlWindow glwin(10,10,300,300); glwin.end(); // Just in case! // Make a group to enclose the outputs and legends, // to control resizing behaviour Fl_Group controls(2,312,316,126); controls.begin(); controls.box(FL_FLAT_BOX); // 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(); // FPS target control set_fps = new Fl_Spinner(140,318+90, 60, 25, "Target"); set_fps->minimum(5); set_fps->maximum(200); set_fps->value(100); set_fps->callback((Fl_Callback*)cb_set_fps); set_fps->when(FL_WHEN_CHANGED); set_fps->clear_visible_focus(); // Toggle between idle loop or target-framerate set_idle = new Fl_Check_Button(60,318+90,25, 25, "Idle"); set_idle->down_box(FL_DOWN_BOX); set_idle->align(Fl_Align(FL_ALIGN_LEFT)); set_idle->tooltip("Use the idle loop, rather \nthan the target FPS"); set_idle->callback((Fl_Callback*)cb_set_idle, (void *)&glwin); set_idle->when(FL_WHEN_CHANGED); set_idle->clear_visible_focus(); // Legend Fl_Box box(210,318,100,115,"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_ENGRAVED_BOX); controls.end(); controls.resizable(box); window.end(); window.resizable(glwin); 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 SELEX Galileo Ltd Registered Office: Sigma House, Christopher Martin Road, Basildon, Essex SS14 3EL A company registered in England & Wales. Company no. 02426132 ******************************************************************** This email and any attachments are confidential to the intended recipient and may also be privileged. If you are not the intended recipient please delete it from your system and notify the sender. You should not copy it or use it for any purpose nor disclose or distribute its contents to any other person. ******************************************************************** _______________________________________________ fltk mailing list fltk@easysw.com http://lists.easysw.com/mailman/listinfo/fltk