#!/usr/bin/env perl
use strict;
$^W=1;
use ToyGL ':all';
use ToyGL::GLUT ':all';
use Math::Quaternion;
use Math::Trig;
use Imager;
my $orientation = new Math::Quaternion;
my ($geomx,$geomy,$geomz) = (0,0,-5);
my $nearclip = 0.1;
my $mousescale = 0.01;
my $zoomscale=0.02;
my $midtranslates = 0; # 1 for middle button to translate, 0 for zoom.
my $wsize = 256; # Window size
my %buttonstate = ( GLUT_LEFT_BUTTON,0,
GLUT_MIDDLE_BUTTON,0,
GLUT_RIGHT_BUTTON,0);
my ($clickx,$clicky)=(0,0); # Coordinates of last mouse click
my ($screenx,$screeny) = ($wsize,$wsize);
my $sphererad = $screeny*0.5; # Radius of trackball sphere
glutInit;
glutInitWindowSize($screenx,$screeny);
glutInitWindowPosition($wsize,0);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
my $window = glutCreateWindow("GLUT window");
init_gl();
glutDisplayFunc(\&displayfunc);
glutReshapeFunc( \&reshapefunc);
glutMouseFunc(\&mousefunc);
glutMotionFunc(\&motionfunc);
glutMainLoop;
sub init_gl {
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glClearColor(0.0,0.0,0.0,0.0);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
glEnable(GL_BLEND);
glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexEnv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
glEnable(GL_TEXTURE_2D);
glFrontFace(GL_CCW);
my $img = Imager->new;
file => 'star.png',
type => 'png',
) or die("Could not open image file");
glTexImage2D(image=>$img);
}
sub reshapefunc {
my ($w,$h) = @_;
($screenx,$screeny) = @_;
$sphererad = $screeny*0.5;
print "Reshaped to $w x $h\n";
glViewport(0,0,$w,$h);
}
sub displayfunc{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
# Set up perspective projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,$screenx/$screeny,$nearclip,1024.0 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslate($geomx,$geomy,$geomz);
my @m = $orientation->matrix4x4;
my ($theta,$phi);
my $dtheta = pi/16;
my $dphi = 2*pi/12;
for ($theta=$dtheta;$theta<pi;$theta+=$dtheta) {
for ($phi=0;$phi<2*pi;$phi+=$dphi) {
my $r = 5.0;
my $x = sin($theta)*cos($phi);
my $y = sin($theta)*sin($phi);
glColor(
glPushMatrix;
glTranslate($r*$x,$r*$y,$r*$z);
draw_star();
glPopMatrix;
}
}
glFlush();
glutSwapBuffers();
}
sub postredisplay {
glutPostRedisplay();
}
sub mousefunc {
my ($button,$state,$x,$y) = @_;
($clickx,$clicky) = ($x,$y);
$buttonstate{$button} = (GLUT_DOWN == $state) ? 1 : 0;
}
sub motionfunc {
my ($x,$y) = @_;
my ($left,$mid,$right) =
@buttonstate{GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON};
if ($left) {
mouserotatemotion($clickx,$clicky,$x,$y);
($clickx,$clicky) = ($x,$y);
} elsif ($mid) {
if ($midtranslates) {
mousetransmotion($clickx,$clicky,$x,$y);
} else {
mousezoommotion($y-$clicky);
}
($clickx,$clicky) = ($x,$y);
} elsif ($right) {
}
}
sub mouserotatemotion {
my ($x0,$y0,$x1,$y1) = @_;
my $s = $sphererad;
my $my = $x1-$x0;
my $mx = $y1-$y0;
my $m=sqrt($mx*$mx+$my*$my);
my $theta;
if (($m>0) && ($m<$s)) {
$theta = $m/$s;
$mx /= $m;
$my /= $m;
my $rotquat = Math::Quaternion::rotation($theta,$mx,$my,0.0);
$orientation = $rotquat * $orientation;
}
postredisplay;
}
sub mousetransmotion {
my ($x0,$y0,$x1,$y1) = @_;
$geomx += $mousescale * ($x1-$x0);
$geomy += $mousescale * ($y0-$y1);
postredisplay;
}
sub mousezoommotion {
$geomz -= $zoomscale*$dz;
postredisplay;
}
{
my $lastidno = 0;
sub makeid {
}
}
sub draw_star {
my @polydata = (
[ 0, 1],
[ 1, 1],
[ 1, 0],
[ 0, 0],
);
# Grab the modelview matrix into @m
my @m= glGet
(GL_MODELVIEW_MATRIX
);
# Set non-translational part to the identity matrix.
$m[0] = $m[5] = $m[10] = 1.0;
$m[1] = $m[2] = $m[4] = $m[6]
= $m[8] = $m[9] = 0.0;
# Load this as the new modelview matrix.
# Draw a quad textured with the star.
glBegin(GL_QUADS);
for (0..3) {
my @a = @{$polydata[$_]};
glTexCoord(@a);
glVertex(@a);
}
glEnd;
}