Qore Programming Language

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

hanoi demo

E-mail Print PDF

This is a tower of hanoi example for opengl.  The C source was ported to Qore.

Unfortunately the programs runs so fast that I was not able to get a screenshot before it finished (source code below):

opengl hanoi demo

#!/usr/bin/env qore

# hanoi.c - written by Greg Humphreys while an intern at SGI

%require-our

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

const WIDTH = 800.0;
const HEIGHT = 400.0;

our $motion = GL_TRUE;
our $back_wall = GL_FALSE;
our $xangle = 0;
our $yangle = 0;
our $xlangle = 0;
our $ylangle = 0;

const wallz = -(WIDTH/2);
const DISK_HEIGHT = 20;

our $NUM_DISKS = 11;

const HANOI_SOLVE = 0;
const HANOI_QUIT = 1;
const HANOI_LIGHTING = 2;
const HANOI_WALL = 3;
const HANOI_FOG = 4;

const lightOneDirection = (0, 0, -1);
const lightOnePosition  = (200, 100, 300, 1);
const lightOneColor     = (1.0, 1.0, 0.5, 1.0);

const lightTwoDirection = (0, 0, -1);
const lightTwoPosition  = (600, 100, 300, 1);
const lightTwoColor     = (1.0, 0.0, 0.3, 1.0);

const lightZeroPosition = (400, 200, 300, 1);
const lightZeroColor    = (0.3, 0.3, 0.3, 0.3);

const diskColor         = (1.0, 1.0, 1.0, 0.8);
const poleColor         = (1.0, 0.2, 0.2, 0.8);

our $poles = ((), (), (), ());

sub push($which, $size)
{
    push $poles[$which], $size;
}

sub pop($which)
{
    return pop $poles[$which];
}

our $moves = ();

sub init()
{
    for (my $i = 1; $i <= $NUM_DISKS; $i++) {
	glNewList($i, GL_COMPILE);
	{
	    glutSolidTorus(DISK_HEIGHT / 2, 5 * $i, 15, 15);
	}
	glEndList();
    }
    glNewList($NUM_DISKS + 1, GL_COMPILE);
    {
	glutSolidCone(10, ($NUM_DISKS + 1) * DISK_HEIGHT, 20, 20);
    }
    glEndList();
}

sub mpop()
{
    shift $moves;
}

sub mpush($t, $f)
{
    push $moves, ( "t" : $t, "f" : $f );
}

sub keyboard($key, $x, $y)
{
    switch ($key) {
	case 27:             /* ESC */
	case 113: #'q':
	case 81:  #'Q':
	    exit(0);
    }
}

sub update()
{
    glutPostRedisplay();
}

sub DrawPost($xcenter)
{
    glPushMatrix();
    {
	glTranslatef($xcenter, 0, 0);
	glRotatef(90, -1, 0, 0);
	glCallList($NUM_DISKS + 1);
    } glPopMatrix();
}

sub DrawPosts()
{
    glColor3fv(poleColor);
    glLineWidth(10);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, poleColor);
    DrawPost(WIDTH / 4);
    DrawPost(2 * WIDTH / 4);
    DrawPost(3 * WIDTH / 4);
}

sub DrawDisk($xcenter, $ycenter, $size)
{
    glPushMatrix();
    {
	glTranslatef($xcenter, $ycenter, 0);
	glRotatef(90, 1, 0, 0);
	glCallList($size);
    }
    glPopMatrix();
}

sub DrawDooDads()
{
    my ($xcenter, $ycenter);
    glColor3fv(diskColor);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, diskColor);
    for (my $i = 1; $i <= 3; $i++) {
	$xcenter = $i * WIDTH / 4;

	my $rl = reverse($poles[$i]);
	$ycenter = DISK_HEIGHT * elements $rl - DISK_HEIGHT / 2;
	for (my $j = 0; $j < elements $rl; ++$j) {
	    my $size = $rl[$j];
	    DrawDisk($xcenter, $ycenter, $size);
	    $ycenter -= DISK_HEIGHT;
	}
    }
}

sub mov($n, $f, $t)
{
    my $o;

    if ($n == 1) {
	mpush($t, $f);
	return;
    }
    $o = 6 - ($f + $t);
    mov($n - 1, $f, $o);
    mov(1, $f, $t);
    mov($n - 1, $o, $t);
}

const wallcolor = (0, 0.3, 1, 1);

sub DrawWall()
{
    glColor3fv(wallcolor);
    for (my $i = 0; $i < WIDTH; $i += 10) {
	for (my $j = 0; $j < HEIGHT; $j += 10) {
	    glBegin(GL_POLYGON);
	    {
		glNormal3f(0, 0, 1);
		glVertex3f($i + 10, $j, wallz);
		glVertex3f($i + 10, $j + 10, wallz);
		glVertex3f($i, $j + 10, wallz);
		glVertex3f($i, $j, wallz);
	    }
	    glEnd();
	}
    }
}

sub draw()
{
    my ($t, $f);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if ($back_wall) {
	glMaterialfv(GL_FRONT, GL_DIFFUSE, wallcolor);
	DrawWall();
    }
    glPushMatrix();
    {
	glTranslatef(WIDTH / 2, HEIGHT / 2, 0);
	glRotatef($xlangle, 0, 1, 0);
	glRotatef($ylangle, 1, 0, 0);
	glTranslatef(-WIDTH / 2, -HEIGHT / 2, 0);
	glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);
    }
    glPopMatrix();

    glPushMatrix();
    {
	glTranslatef(WIDTH / 2, HEIGHT / 2, 0);
	glRotatef($xangle, 0, 1, 0);
	glRotatef($yangle, 1, 0, 0);
	glTranslatef(-WIDTH / 2, -HEIGHT / 2, 0);
	DrawPosts();
	DrawDooDads();
    }
    glPopMatrix();
    if ($motion && elements $moves) {
	$t = $moves[0].t;
	$f = $moves[0].f;
	push($t, pop($f));
	mpop();
    }
    glutSwapBuffers();
}

sub hanoi_menu($value)
{
    switch ($value) {
    case HANOI_SOLVE:
	$motion = !$motion;
	if($motion) {
	    glutIdleFunc(\update());
	} else {
	    glutIdleFunc();
	}
	break;
    case HANOI_LIGHTING:
	if (glIsEnabled(GL_LIGHTING))
	    glDisable(GL_LIGHTING);
	else
	    glEnable(GL_LIGHTING);
	break;
    case HANOI_WALL:
	$back_wall = !$back_wall;
	break;
    case HANOI_FOG:
	if (glIsEnabled(GL_FOG))
	    glDisable(GL_FOG);
	else {
	    glEnable(GL_FOG);
	    glFogi(GL_FOG_MODE, GL_EXP);
	    glFogf(GL_FOG_DENSITY, 0.01);
	}
	break;
    case HANOI_QUIT:
	exit(0);
	break;
    }
    glutPostRedisplay();
}

our ($oldx, $oldy);

our $leftb = GL_FALSE;
our $middleb = GL_FALSE;

sub hanoi_mouse($button, $state, $x, $y)
{
    if ($button == GLUT_LEFT_BUTTON) {
	$oldx = $x;
	$oldy = $y;
	if ($state == GLUT_DOWN)
	    $leftb = GL_TRUE;
	else
	    $leftb = GL_FALSE;
    }
    if ($button == GLUT_MIDDLE_BUTTON) {
	$oldx = $x;
	$oldy = $y;
	if ($state == GLUT_DOWN)
	    $middleb = GL_TRUE;
	else
	    $middleb = GL_FALSE;
    }
}

sub hanoi_visibility($state)
{
    if ($state == GLUT_VISIBLE && $motion) {
	glutIdleFunc(\update());
    } else {
	glutIdleFunc();
    }
}

sub hanoi_motion($x, $y)
{
    if ($leftb) {
      $xangle -= ($x - $oldx);
      $yangle -= ($y - $oldy);
    }
    if ($middleb) {
	$xlangle -= ($x - $oldx);
	$ylangle -= ($y - $oldy);
    }
    $oldx = $x;
    $oldy = $y;
    glutPostRedisplay();
}

const opts = ( "disks" : "n:i" );

sub main()
{
    my $p = new GetOpt(opts);
    my $o = $p.parse(\$ARGV);

    glutInit(\$ARGV);

    if ($o.disks)
	$NUM_DISKS = $o.disks;

    glutInitWindowSize(WIDTH, HEIGHT);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("Hanoi");

    glutDisplayFunc(\draw());
    glutKeyboardFunc(\keyboard());

    glViewport(0, 0, WIDTH, HEIGHT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, WIDTH, 0, HEIGHT, -10000, 10000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glClearColor(0, 0, 0, 0);
    glClearDepth(1.0);

    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);

    #glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);

    glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition);
    glLightfv(GL_LIGHT1, GL_DIFFUSE, lightOneColor);
    glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 10);
    glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, lightOneDirection);
    glEnable(GL_LIGHT1);

    glLightfv(GL_LIGHT2, GL_POSITION, lightTwoPosition);
    glLightfv(GL_LIGHT2, GL_DIFFUSE, lightTwoColor);
    #glLightf(GL_LIGHT2,GL_LINEAR_ATTENUATION,.005);
    glLightf(GL_LIGHT2, GL_SPOT_CUTOFF, 10);
    glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION, lightTwoDirection);
    glEnable(GL_LIGHT2);

    glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
    glEnable(GL_LIGHT0);

    glEnable(GL_LIGHTING);

    glutMouseFunc(\hanoi_mouse());
    glutMotionFunc(\hanoi_motion());
    glutVisibilityFunc(\hanoi_visibility());

    glutCreateMenu(\hanoi_menu());
    glutAddMenuEntry("Solve", HANOI_SOLVE);
    glutAddMenuEntry("Lighting", HANOI_LIGHTING);
    glutAddMenuEntry("Back Wall", HANOI_WALL);
    glutAddMenuEntry("Fog", HANOI_FOG);
    glutAddMenuEntry("Quit", HANOI_QUIT);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
    init();

    for (my $i = 0; $i < $NUM_DISKS; $i++)
	push(1, $NUM_DISKS - $i);
    mov($NUM_DISKS, 1, 3);

    glutMainLoop();
}

main();

Last Updated on Saturday, 25 December 2010 19:46