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