#!/usr/bin/perl -w # # Draws a gear. # # This code is originally from Qt-1.44, by Troll Tech # # Portions of this code have been borrowed from Brian Paul's Mesa # distribution. # package GearWidget; use OpenGL qw(:all); use Qt; use Qt::attributes qw( gear1 gear2 gear3 view_rotx view_roty view_rotz angle ); use Qt::isa qw(Qt::GLWidget); # # 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 # sub gear { my($inner_radius, $outer_radius, $width, $teeth, $tooth_depth) = @_; my $i; my($r0, $r1, $r2); my($angle, $da); my($u, $v, $len); $r0 = $inner_radius; $r1 = $outer_radius - $tooth_depth/2.0; $r2 = $outer_radius + $tooth_depth/2.0; my $pi = 3.141592654; $da = 2.0*$pi / $teeth / 4.0; glShadeModel(GL_FLAT); glNormal3f(0.0, 0.0, 1.0); # draw front face glBegin(GL_QUAD_STRIP); for $i (0 .. $teeth) { $angle = $i * 2.0*$pi / $teeth; glVertex3f($r0*cos($angle), $r0*sin($angle), $width*0.5); glVertex3f($r1*cos($angle), $r1*sin($angle), $width*0.5); 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*$pi / $teeth / 4.0; for $i (0 .. $teeth-1) { $angle = $i * 2.0*$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(); glNormal3f(0.0, 0.0, -1.0); # draw back face glBegin(GL_QUAD_STRIP); for $i (0 .. $teeth) { $angle = $i * 2.0*$pi / $teeth; glVertex3f($r1*cos($angle), $r1*sin($angle), -$width*0.5); glVertex3f($r0*cos($angle), $r0*sin($angle), -$width*0.5); 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*$pi / $teeth / 4.0; for $i (0 .. $teeth-1) { $angle = $i * 2.0*$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 .. $teeth-1) { $angle = $i * 2.0*$pi / $teeth; glVertex3f($r1*cos($angle), $r1*sin($angle), $width*0.5); glVertex3f($r1*cos($angle), $r1*sin($angle), -$width*0.5); $u = $r2*cos($angle+$da) - $r1*cos($angle); $v = $r2*sin($angle+$da) - $r1*sin($angle); $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(); glShadeModel(GL_SMOOTH); # draw inside radius cylinder glBegin(GL_QUAD_STRIP); for $i (0 .. $teeth) { $angle = $i * 2.0*$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(); } sub draw { angle += 2.0; view_roty += 1.0; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 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); glPushMatrix(); glTranslatef(-3.0, -2.0, 0.0); glRotatef(angle, 0.0, 0.0, 1.0); glCallList(gear1); glPopMatrix(); glPushMatrix(); glTranslatef(3.1, -2.0, 0.0); glRotatef(-2.0*angle-9.0, 0.0, 0.0, 1.0); glCallList(gear2); glPopMatrix(); glPushMatrix(); glTranslatef(-3.1, 2.2, -1.8); glRotatef(90.0, 1.0, 0.0, 0.0); glRotatef(2.0*angle-2.0, 0.0, 0.0, 1.0); glCallList(gear3); glPopMatrix(); glPopMatrix(); } sub NEW { shift->SUPER::NEW(@_); this->startTimer(10); view_rotx = 20.0; view_roty = 30.0; view_rotz = 0.0; angle = 0.0; } sub initializeGL { my $pos = [ 5.0, 5.0, 10.0, 1.0 ]; my $red = [ 0.8, 0.1, 0.0, 1.0 ]; my $green = [ 0.0, 0.8, 0.2, 1.0 ]; my $blue = [ 0.2, 0.2, 1.0, 1.0 ]; glLightfv_p(GL_LIGHT0, GL_POSITION, @$pos); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); # make the gears gear1 = glGenLists(1); glNewList(gear1, GL_COMPILE); glMaterialfv_p(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, @$red); gear(1.0, 4.0, 1.0, 20, 0.7); glEndList(); gear2 = glGenLists(1); glNewList(gear2, GL_COMPILE); glMaterialfv_p(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, @$green); gear(0.5, 2.0, 2.0, 10, 0.7); glEndList(); gear3 = glGenLists(1); glNewList(gear3, GL_COMPILE); glMaterialfv_p(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, @$blue); gear(1.3, 2.0, 0.5, 10, 0.7); glEndList(); glEnable(GL_NORMALIZE); } sub resizeGL { my($width, $height) = @_; my $w = $width / $height; my $h = 1.0; glViewport(0, 0, $width, $height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-$w, $w, -$h, $h, 5.0, 60.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -40.0); } sub paintGL { draw(); } sub timerEvent { updateGL(); } package main; use Qt; use GearWidget; $app = Qt::Application(\@ARGV); if(!Qt::GLFormat::hasOpenGL()) { warn("This system has no OpenGL support. Exiting."); exit -1; } $w = GearWidget; $app->setMainWidget($w); $w->show; exit $app->exec;