Qore Programming Language

  • Increase font size
  • Default font size
  • Decrease font size

gears2 demo

E-mail Print PDF

This is another opengl C demo entitled "gears" ported to Qore, before I ported it I thought it was the classic "gears" demo.

It's actually a different one, but it still looks pretty neat.  I'm not sure who was the original author.

Here is a screenshot of the Qore code running on OSX (source code below):

opengl gears2 demo

#!/usr/bin/env qore

# this one is pretty slow compared to gears.q

# the glut module automatically loads the opengl module
%requires glut

%require-our

const d_near = 1.0;
const d_far = 2000.0;

our $circle_subdiv;

our $gear_profile = (( "rad" : 0.000, "wid" : 0.0 ),
		     ( "rad" : 0.300, "wid" : 7.0 ),
		     ( "rad" : 0.340, "wid" : 0.4 ),
		     ( "rad" : 0.550, "wid" : 0.64 ),
		     ( "rad" : 0.600, "wid" : 0.4 ),
		     ( "rad" : 0.950, "wid" : 1.0 ));

our $a1 = 27.0;
our $a2 = 67.0;
our $a3 = 47.0;
our $a4 = 87.0;
our $i1 = 1.2;
our $i2 = 3.1;
our $i3 = 2.3;
our $i4 = 1.1;

sub gear($nt, $wd, $ir, $or, $tp, $tip, $ip)
{
    # * nt - number of teeth
    # * wd - width of gear at teeth
    # * ir - inside radius absolute scale
    # * or - radius at outside of wheel (tip of tooth) ratio of ir
    # * tp - ratio of tooth in slice of circle (0..1] (1 = teeth are touching at base)
    # * tip - ratio of tip of tooth (0..tp] (cant be wider that base of tooth)
    # * ns - number of elements in wheel width profile
    # * *ip - list of float pairs {start radius, width, ...} (width is ratio to wd)

    # gear lying on xy plane, z for width. all normals calulated (normalized)

    my $ns = elements $ip;

    my $prev;
    my ($k, $t);

    # estimate # times to divide circle
    if ($nt <= 0)
	$circle_subdiv = 64;
    else {
	# lowest multiple of number of teeth
	$circle_subdiv = $nt;
	while ($circle_subdiv < 64)
	    $circle_subdiv += $nt;
    }

    # --- draw wheel face ---

    # draw horzontal, vertical faces for each section. if first
    # section radius not zero, use wd for 0.. first if ns == 0
    # use wd for whole face. last width used to edge.

    if ($ns <= 0) {
	flat_face(0.0, $ir, $wd);
    } else {
	# draw first flat_face, then continue in loop
	if ($ip[0].rad > 0.0) {
	    flat_face(0.0, $ip[0].rad * $ir, $wd);
	    $prev = $wd;
	    $t = 0;
	} else {
	    flat_face(0.0, $ip[1].rad * $ir, $ip[0].wid * $wd);
	    $prev = $ip[0].wid;
	    $t = 1;
	}
	for ($k = $t; $k < $ns; $k++) {
	    if ($prev < $ip[$k].wid) {
		draw_inside($prev * $wd, $ip[$k].wid * $wd, $ip[$k].rad * $ir);
	    } else {
		draw_outside($prev * $wd, $ip[$k].wid * $wd, $ip[$k].rad * $ir);
	    }
	    $prev = $ip[$k].wid;
	    # - draw to edge of wheel, add final face if needed
		if ($k == $ns - 1) {
		    flat_face($ip[$k].rad * $ir, $ir, $ip[$k].wid * $wd);

		    # now draw side to match tooth rim
		    if ($ip[$k].wid < 1.0) {
			draw_inside($ip[$k].wid * $wd, $wd, $ir);
		    } else {
			draw_outside($ip[$k].wid * $wd, $wd, $ir);
		    }
		} else {
		    flat_face($ip[$k].rad * $ir, $ip[$k + 1].rad * $ir, $ip[$k].wid * $wd);
		}
	}
    }

    # --- tooth side faces ---
    tooth_side($nt, $ir, $or, $tp, $tip, $wd);

    # --- tooth hill surface ---
}

sub tooth_side($nt, $ir, $or, $tp, $tip, $wd)
{
    my $i;
    my $end = 2.0 * M_PI / $nt;
    my ($x, $y);
    my ($s, $c);


    my $bound = 2.0 * M_PI - $end / 4.0;
    $or = $or * $ir;         # or is really a ratio of ir
    for ($i = 0.0; $i < $bound; $i += $end) {

	#printf("tooth_side(%n, %n, %n, %n, %n, %n) i=%n, bound=%n, end=%n\n", $nt, $ir, $or, $tp, $tip, $wd, $i, $bound, $end);


	$c[0] = cos($i);
	$s[0] = sin($i);
	$c[1] = cos($i + $end * (0.5 - $tip / 2));
	$s[1] = sin($i + $end * (0.5 - $tip / 2));
	$c[2] = cos($i + $end * (0.5 + $tp / 2));
	$s[2] = sin($i + $end * (0.5 + $tp / 2));

	$x[0] = $ir * $c[0];
	$y[0] = $ir * $s[0];
	$x[5] = $ir * cos($i + $end);
	$y[5] = $ir * sin($i + $end);
	# ---treat veritices 1,4 special to match strait edge of face
	$x[1] = $x[0] + ($x[5] - $x[0]) * (0.5 - $tp / 2);
	$y[1] = $y[0] + ($y[5] - $y[0]) * (0.5 - $tp / 2);
	$x[4] = $x[0] + ($x[5] - $x[0]) * (0.5 + $tp / 2);
	$y[4] = $y[0] + ($y[5] - $y[0]) * (0.5 + $tp / 2);
	$x[2] = $or * cos($i + $end * (0.5 - $tip / 2));
	$y[2] = $or * sin($i + $end * (0.5 - $tip / 2));
	$x[3] = $or * cos($i + $end * (0.5 + $tip / 2));
	$y[3] = $or * sin($i + $end * (0.5 + $tip / 2));

	# draw face trapezoids as 2 tmesh
	glNormal3f(0.0, 0.0, 1.0);
	glBegin(GL_TRIANGLE_STRIP);
	glVertex3f($x[2], $y[2], $wd / 2);
	glVertex3f($x[1], $y[1], $wd / 2);
	glVertex3f($x[3], $y[3], $wd / 2);
	glVertex3f($x[4], $y[4], $wd / 2);
	glEnd();

	glNormal3f(0.0, 0.0, -1.0);
	glBegin(GL_TRIANGLE_STRIP);
	glVertex3f($x[2], $y[2], -$wd / 2);
	glVertex3f($x[1], $y[1], -$wd / 2);
	glVertex3f($x[3], $y[3], -$wd / 2);
	glVertex3f($x[4], $y[4], -$wd / 2);
	glEnd();

	# draw inside rim pieces
	glNormal3f($c[0], $s[0], 0.0);
	glBegin(GL_TRIANGLE_STRIP);
	glVertex3f($x[0], $y[0], -$wd / 2);
	glVertex3f($x[1], $y[1], -$wd / 2);
	glVertex3f($x[0], $y[0], $wd / 2);
	glVertex3f($x[1], $y[1], $wd / 2);
	glEnd();

	# draw up hill side
	{
	    my ($a, $b, $n);
	    # calculate normal of face
	    $a = $x[2] - $x[1];
	    $b = $y[2] - $y[1];
	    $n = 1.0 / sqrt($a * $a + $b * $b);
	    $a = $a * $n;
	    $b = $b * $n;
	    glNormal3f($b, -$a, 0.0);
	}
	glBegin(GL_TRIANGLE_STRIP);
	glVertex3f($x[1], $y[1], -$wd / 2);
	glVertex3f($x[2], $y[2], -$wd / 2);
	glVertex3f($x[1], $y[1], $wd / 2);
	glVertex3f($x[2], $y[2], $wd / 2);
	glEnd();
	# draw top of hill
	glNormal3f($c[1], $s[1], 0.0);
	glBegin(GL_TRIANGLE_STRIP);
	glVertex3f($x[2], $y[2], -$wd / 2);
	glVertex3f($x[3], $y[3], -$wd / 2);
	glVertex3f($x[2], $y[2], $wd / 2);
	glVertex3f($x[3], $y[3], $wd / 2);
	glEnd();

	# draw down hill side
	{
	    my ($a, $b, $c);
	    # calculate normal of face
	    $a = $x[4] - $x[3];
	    $b = $y[4] - $y[3];
	    $c = 1.0 / sqrt($a * $a + $b * $b);
	    $a = $a * $c;
	    $b = $b * $c;
	    glNormal3f($b, -$a, 0.0);
	}
	glBegin(GL_TRIANGLE_STRIP);
	glVertex3f($x[3], $y[3], -$wd / 2);
	glVertex3f($x[4], $y[4], -$wd / 2);
	glVertex3f($x[3], $y[3], $wd / 2);
	glVertex3f($x[4], $y[4], $wd / 2);
	glEnd();
	# inside rim part
	glNormal3f($c[2], $s[2], 0.0);
	glBegin(GL_TRIANGLE_STRIP);
	glVertex3f($x[4], $y[4], -$wd / 2);
	glVertex3f($x[5], $y[5], -$wd / 2);
	glVertex3f($x[4], $y[4], $wd / 2);
	glVertex3f($x[5], $y[5], $wd / 2);
	glEnd();
    }
}

sub flat_face($ir, $or, $wd)
{
    my $i;
    my $w;

    # draw each face (top & bottom )
    #printf("Face   : %n..%n wid=%n\n", $ir, $or, $wd);
    if ($wd == 0.0)
	return;
    for ($w = $wd / 2; $w > -$wd; $w -= $wd) {
	if ($w > 0.0)
	    glNormal3f(0.0, 0.0, 1.0);
	else
	    glNormal3f(0.0, 0.0, -1.0);

	if ($ir == 0.0) {
	    # draw as t-fan
	    glBegin(GL_TRIANGLE_FAN);
	    glVertex3f(0.0, 0.0, $w);  #/* center */
	    glVertex3f($or, 0.0, $w);
	    for ($i = 1; $i < $circle_subdiv; $i++) {
		glVertex3f(cos(2.0 * M_PI * $i / $circle_subdiv) * $or,
			   sin(2.0 * M_PI * $i / $circle_subdiv) * $or, $w);
	    }
	    glVertex3f($or, 0.0, $w);
	    glEnd();
	} else {
	    #/* draw as tmesh */
	    glBegin(GL_TRIANGLE_STRIP);
	    glVertex3f($or, 0.0, $w);
	    glVertex3f($ir, 0.0, $w);
	    for ($i = 1; $i < $circle_subdiv; $i++) {
		glVertex3f(cos(2.0 * M_PI * $i / $circle_subdiv) * $or,
			   sin(2.0 * M_PI * $i / $circle_subdiv) * $or, $w);
		glVertex3f(cos(2.0 * M_PI * $i / $circle_subdiv) * $ir,
			   sin(2.0 * M_PI * $i / $circle_subdiv) * $ir, $w);
	    }
	    glVertex3f($or, 0.0, $w);
	    glVertex3f($ir, 0.0, $w);
	    glEnd();
	}
    }
}

sub draw_inside($w1, $w2, $rad)
{
    my ($i, $j);
    my ($c, $s);
    #printf("Inside : wid=%n..%n rad=%n\n", $w1, $w2, $rad);
    if ($w1 == $w2)
	return;

    $w1 = $w1 / 2;
    $w2 = $w2 / 2;
    for ($j = 0; $j < 2; $j++) {
	if ($j == 1) {
	    $w1 = -$w1;
	    $w2 = -$w2;
	}
	glBegin(GL_TRIANGLE_STRIP);
	glNormal3f(-1.0, 0.0, 0.0);
	glVertex3f($rad, 0.0, $w1);
	glVertex3f($rad, 0.0, $w2);
	for ($i = 1; $i < $circle_subdiv; $i++) {
	    $c = cos(2.0 * M_PI * $i / $circle_subdiv);
	    $s = sin(2.0 * M_PI * $i / $circle_subdiv);
	    glNormal3f(-$c, -$s, 0.0);
	    glVertex3f($c * $rad,
		       $s * $rad,
		       $w1);
	    glVertex3f($c * $rad,
		       $s * $rad,
		       $w2);
	}
	glNormal3f(-1.0, 0.0, 0.0);
	glVertex3f($rad, 0.0, $w1);
	glVertex3f($rad, 0.0, $w2);
	glEnd();
    }
}

sub draw_outside($w1, $w2, $rad)
{
    my ($i, $j);
    my ($c, $s);
    #printf("Outside: wid=%n..%n rad=%n\n", $w1, $w2, $rad);

    if ($w1 == $w2)
	return;

    $w1 = $w1 / 2;
    $w2 = $w2 / 2;
    for ($j = 0; $j < 2; $j++) {
	if ($j == 1) {
	    $w1 = -$w1;
	    $w2 = -$w2;
	}
	glBegin(GL_TRIANGLE_STRIP);
	glNormal3f(1.0, 0.0, 0.0);
	glVertex3f($rad, 0.0, $w1);
	glVertex3f($rad, 0.0, $w2);
	for ($i = 1; $i < $circle_subdiv; $i++) {
	    $c = cos(2.0 * M_PI * $i / $circle_subdiv);
	    $s = sin(2.0 * M_PI * $i / $circle_subdiv);
	    glNormal3f($c, $s, 0.0);
	    glVertex3f($c * $rad,
		       $s * $rad,
		       $w1);
	    glVertex3f($c * $rad,
		       $s * $rad,
		       $w2);
	}
	glNormal3f(1.0, 0.0, 0.0);
	glVertex3f($rad, 0.0, $w1);
	glVertex3f($rad, 0.0, $w2);
	glEnd();
    }
}

sub oneFrame()
{
    #printf("oneFrame()\n");
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glPushMatrix();
    glTranslatef(0.0, 0.0, -4.0);
    glRotatef($a3, 1.0, 1.0, 1.0);
    glRotatef($a4, 0.0, 0.0, -1.0);
    glTranslatef(0.14, 0.2, 0.0);
    gear(76,
	 0.4, 2.0, 1.1,
	 0.4, 0.04,
	 $gear_profile);
    glPopMatrix();

    glPushMatrix();
    glTranslatef(0.1, 0.2, -3.8);
    glRotatef($a2, -4.0, 2.0, -1.0);
    glRotatef($a1, 1.0, -3.0, 1.0);
    glTranslatef(0.0, -0.2, 0.0);
    gear(36,
	 0.4, 2.0, 1.1,
	 0.7, 0.2,
	 $gear_profile);
    glPopMatrix();

    $a1 += $i1;
    if ($a1 > 360.0)
	$a1 -= 360.0;
    if ($a1 < 0.0)
	$a1 -= 360.0;
    $a2 += $i2;
    if ($a2 > 360.0)
	$a2 -= 360.0;
    if ($a2 < 0.0)
	$a2 -= 360.0;
    $a3 += $i3;
    if ($a3 > 360.0)
	$a3 -= 360.0;
    if ($a3 < 0.0)
	$a3 -= 360.0;
    $a4 += $i4;
    if ($a4 > 360.0)
	$a4 -= 360.0;
    if ($a4 < 0.0)
	$a4 -= 360.0;
    glutSwapBuffers();
}

sub display()
{
    #printf("display()");
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

sub myReshape($w, $h)
{
    #printf("myReshape(%n, %n)\n", $w, $h);
    glViewport(0, 0, $w, $h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-1.0, 1.0, -1.0, 1.0, d_near, d_far);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

sub visibility($status)
{
    #printf("visibility(%n)\n", $status);
    if ($status == GLUT_VISIBLE) {
	glutIdleFunc(\oneFrame());
    } else {
	glutIdleFunc();
    }
}

sub myinit()
{
    my $f;
    glClearColor(0.0, 0.0, 0.0, 0.0);
    myReshape(640, 480);
    # glShadeModel(GL_FLAT);
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glEnable(GL_LIGHTING);

    glLightf(GL_LIGHT0, GL_SHININESS, 1.0);
    $f[0] = 1.3;
    $f[1] = 1.3;
    $f[2] = -3.3;
    $f[3] = 1.0;
    glLightfv(GL_LIGHT0, GL_POSITION, $f);
    $f[0] = 0.8;
    $f[1] = 1.0;
    $f[2] = 0.83;
    $f[3] = 1.0;
    glLightfv(GL_LIGHT0, GL_SPECULAR, $f);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, $f);
    glEnable(GL_LIGHT0);

    glLightf(GL_LIGHT1, GL_SHININESS, 1.0);
    $f[0] = -2.3;
    $f[1] = 0.3;
    $f[2] = -7.3;
    $f[3] = 1.0;
    glLightfv(GL_LIGHT1, GL_POSITION, $f);
    $f[0] = 1.0;
    $f[1] = 0.8;
    $f[2] = 0.93;
    $f[3] = 1.0;
    glLightfv(GL_LIGHT1, GL_SPECULAR, $f);
    glLightfv(GL_LIGHT1, GL_DIFFUSE, $f);
    glEnable(GL_LIGHT1);

    # gear material
    $f[0] = 0.1;
    $f[1] = 0.15;
    $f[2] = 0.2;
    $f[3] = 1.0;
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, $f);

    $f[0] = 0.9;
    $f[1] = 0.3;
    $f[2] = 0.3;
    $f[3] = 1.0;
    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, $f);

    $f[0] = 0.4;
    $f[1] = 0.9;
    $f[2] = 0.6;
    $f[3] = 1.0;
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, $f);

    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 4);
}

# renamed from "keys" due to keyword conflict in qore
sub keyboard($c, $x, $y)
{
    #printf("keys: c=%s x=%d y=%d\n", $c, $x, $y);
    if ($c == 0x1b)
	exit(0);
}

sub main()
{
    my $mode = GLUT_DOUBLE;

    glutInit(\$ARGV);

    if (elements $ARGV > 1)
	$mode = GLUT_SINGLE;
    glutInitDisplayMode($mode | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(640, 480);
    glutCreateWindow("Gears");

    myinit();
    glutReshapeFunc(\myReshape());
    glutDisplayFunc(\display());
    glutKeyboardFunc(\keyboard());
    glutVisibilityFunc(\visibility());
    glutPostRedisplay();
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glutMainLoop();
}

main();

Last Updated on Saturday, 25 December 2010 19:47