> 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
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk