#!/usr/local/bin/perl
# simple maze thingy
# in case module not "installed" :
BEGIN{ unshift(@INC,"./blib"); unshift(@INC,"../blib"); }
BEGIN{ unshift(@INC,"../blib/arch"); } # 5.002 gamma needs this
BEGIN{ unshift(@INC,"../blib/lib"); } # 5.002 gamma needs this
use OpenGL;
@walldata = (
"****************",
"* * * *",
"* * *** * * *",
"* * * ** * * *",
"* * * * *",
"********** *** *",
"* * *",
"* ***** *** ****",
"* * * * *",
"* * *** * *",
"* * * * * *",
"* ***** **** * *",
"* * * *",
"***** ******** *",
"* * * * *",
"* *** *** ****",
"* * * *",
"****************",
);
$x_size = scalar(@walldata);
$y_size = length($walldata[0]);
($x_size > 3 && $x_size<200) || die "bad data - number of rows $x_size ";
($y_size > 3 && $y_size<200) || die "bad data - number of columns $y_size ";
for($x=0;$x<$x_size;$x++) {
($y_size==length($walldata[$x])) ||
die "line $x of data ",length($walldata[$x]),"/$y_size chars";
$walldata[$x] =~ s/ /0/g;
$walldata[$x] =~ s/\*/1/g;
my(@ww)=split(//,$walldata[$x]);
#print "$wall[$x] - @ww -";
$wall[$x] = \ @ww;
#print "@{$wall[$x]}\n";
}
$s=1;
@cx=(0,0,0,0,$s,$s,$s,$s);
@cy=(0,0,$s,$s,0,0,$s,$s);
@cz=(0,$s,$s,0,0,$s,$s,0);
@cf=(
0, 1, 2, 3,
3, 2, 6, 7,
7, 6, 5, 4,
4, 5, 1, 0,
5, 6, 2, 1,
7, 4, 0, 3,
);
@r=(0.5, 0, 0, 0.5, 1.0, 0);
@g=(0, 0.5, 0, 0.5, 0, 1.0);
@b=(0, 0, 0.5, 0, 1.0, 1.0);
sub drawwalls {
local($x,$y,$dl);
glNewList($dl=glGenLists(1),GL_COMPILE);
for($x=0;$x<$x_size;$x++) {
for($y=0;$y<$y_size;$y++) {
if($wall[$x]->[$y]) {
for($i=0;$i<6;$i++){
if(
$i==4 || $i==5 ||
($i==0 && ($x==0 || !($wall[$x-1]->[$y]))) ||
($i==1 && ($y==$y_size-1 || !($wall[$x]->[$y+1]))) ||
($i==2 && ($x==$x_size-1 || !($wall[$x+1]->[$y]))) ||
($i==3 && ($y==0 || !($wall[$x]->[$y-1])))
) {
glColor3f($r[$i],$g[$i],$b[$i]);
glBegin(GL_POLYGON);
#print " begin poly $x,$y $i\n";
for($j=0;$j<4;$j++){
$k=$cf[$i*4+$j];
glVertex3d($x+$cx[$k],$y+$cy[$k],$cz[$k]);
}
glEnd();
}
}
}
}
}
glColor3f(0,1,0);
glBegin(GL_POLYGON);
glVertex3f(1+0.2,1+0.2,0);
glVertex3f(1+0.2,1+0.8,0);
glVertex3f(1+0.8,1+0.8,0);
glVertex3f(1+0.8,1+0.2,0);
glEnd();
glColor3f(1,0,0);
glBegin(GL_POLYGON);
glVertex3f($x_size-2+0.2,$y_size-2+0.2,0);
glVertex3f($x_size-2+0.2,$y_size-2+0.8,0);
glVertex3f($x_size-2+0.8,$y_size-2+0.8,0);
glVertex3f($x_size-2+0.8,$y_size-2+0.2,0);
glEnd();
glEndList();
$dl;
}
package A;
use OpenGL;
%defaults = (
'name' => 'unnamed',
'x' => 0 ,
'y' => 0 ,
'z' => 0 ,
'dx'=> 0,
'dy'=> 0,
'dz'=> 0,
'angle' => 0,
'dl'=> $main::shot,
);
sub initialize {
my $self=shift;
local %v = @_;
foreach $k (keys(%v)) {
$self->{$k} = $v{$k};
}
$self;
}
sub print{
my $self=shift;
print "\tObject '",$self->{'name'},"' is a '",ref($self),"'\n";
foreach $k (sort keys(%$self)) {
print("\t\t$k\t$self->{$k}\n") if($k cmp 'name');
}
print "\n";
}
sub new {
my $type = shift;
my $self = {};
initialize($self,%defaults);
initialize($self,@_);
push(@objects,$self);
bless $self;
}
sub move {
my $self=shift;
local $h;
($self->{'x'},$self->{'y'},$h) = &main::forward($self->{'x'},
$self->{'y'},
$self->{'x'}+$self->{'dx'},
$self->{'y'}+$self->{'dy'},0.01);
#print "bullet $self->{'x'},$self->{'y'} $self->{'dx'},$self->{'dy'} $self \n";
if($h) {
local($i,$k);
$k=-1;
for($i=0;$i<=$#objects;$i++) {
($k=$i) if($objects[$i] == $self) ;
}
$k==-1 and die "hey k= $k\n";
splice(@objects,$k,1);
$self->{'dl'} = 4;
#print "dead\n";
}
}
sub draw {
my $self=shift;
glPushMatrix();
glTranslatef($self->{'x'},$self->{'y'},$self->{'z'});
glRotatef($self->{'angle'},0,0,1);
#glCallList($self->{'dl'});
glCallList($self->{'dl'});
#glCallList($main::shot);
glPopMatrix ();
}
package main;
sub check_events {
while(XPending) {
my @e=&glpXNextEvent;
my %s;
&$s(@e) if($s=$cb{$e[0]});
}
}
sub intro {
# give a cool intro to the thing
# spin the maze around on 2 axis then
# zoom in to the starting position.
local($spin,$p);
$spin=360*2;
while($spin-=5) {
check_events;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glPushMatrix();
glTranslatef(0,0,-20);
glRotatef($spin, 0.0, 1.0, 1.0);
glTranslatef(-$x_size/2,-$y_size/2,0);
glCallList($walls);
glPopMatrix();
glXSwapBuffers;
}
for($p=0 ; $p <= 1 ; $p+=0.02) {
check_events;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glPushMatrix();
glRotatef(-90*$p,1,0,0);
glRotatef($b*$p,0,0,1);
glTranslatef(-$x*$p + -$x_size/2*(1-$p),-$y*$p+ -$y_size/2*(1-$p),-0.5*$p + -20*(1-$p));
glCallList($walls);
glPopMatrix();
glXSwapBuffers;
}
}
$x=1.5 ; $y=1.5 ; $b = 90 ;
sub forward {
# this routine does wall collision detection
# the inputs to this routine are:
# - the current location
# - the desired location
# - the minimum distance to wall allowed
# returns
# - new coordinates after move
# - whether a wall caused change in target position
# This is really easy with these walls that lie only on axes.
local($x,$y,$px,$py, $bf) = @_;
local($h)=(0);
if($px>int($x)+1.0-$bf && $wall[$x+1]->[$y]) {
$px = int($x)+1.0-$bf;
$h++;
}
if($py>int($y)+1.0-$bf && $wall[$x]->[$y+1]) {
$py = int($y)+1.0-$bf;
$h++;
}
if($px<int($x)+$bf && $wall[$x-1]->[$y]) {
$px = int($x)+$bf;
$h++;
}
if($py<int($y)+$bf && $wall[$x]->[$y-1]) {
$py = int($y)+$bf;
$h++;
}
($px,$py,$h);
}
sub abs {
($_[0] > 0) ? $_[0] : - $_[0];
}
sub nav {
check_events;
# routine for navigating through the maze
$t++;
($px,$py,$pm) = glpXQueryPointer;
$rot = 0;
if ($pm & Button1Mask) { $rot = -1; }
if ($pm & Button3Mask) { $rot = 1; }
$rot = 2*$px/$width - 1 if !$rot && ($pm & Button2Mask);
$b += (( $pm & (ShiftMask)) ?9 :3) * $rot;
if ($pm & Button2Mask) {
$speed = ( $pm & (ShiftMask)) ?0.15 : 0.05;
($x,$y) = forward($x,$y,$x+$speed*sin($b*3.14/180),
$y+$speed*cos($b*3.14/180),0.2);
}
if( $pm & (ControlMask)) {
#print "fire\n";
local($d);
$d=$b + abs($t*7%60-30)-15;
new A(x=>$x,y=>$y,z=>0.5,
dx => 0.08*sin(($d)*3.14/180),dy=>0.08*cos(($d)*3.14/180) ,
dl=>3,angle=>-($d)
);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glPushMatrix();
glRotatef(-90,1,0,0);
glRotatef($b,0,0,1);
glTranslatef(-$x,-$y,-0.5);
glCallList($walls);
# make copy of list since it may get modified during list traversal
@objects = @A::objects;
foreach $obj (@objects) {
$obj->move;
$obj->draw;
}
glPopMatrix();
glXSwapBuffers;
}
$width = 300;
glpOpenWindow(attributes => [GLX_GREEN_SIZE, 1,GLX_RGBA,GLX_DOUBLEBUFFER],
mask => StructureNotifyMask|KeyPressMask,
width=>$width,height=>300);
print <<EOP;
Control: MB1/MB3 - turn left/right, MB2 - go (and turn), Control - shoot a wave
EOP
$cb{&ConfigureNotify} = sub {
local($e,$w,$h)=@_;
glViewport(0,0,$w,$h);
print "new viewport $w,$h\n";
$width = $w;
};
glNewList($shot=3,GL_COMPILE);
glColor3f(0.5,1.0,0.5);
glBegin(GL_POLYGON);
glNormal3f( 0.10, 0.0, 0.0);
glVertex3f( 0.0 , 0.03, -0.04);
glVertex3f( 0.0030 , -0.01, -0.04);
glVertex3f( -0.0030 , -0.01, -0.04);
glEnd();
glEndList();
glNewList($smash=4,GL_COMPILE);
glColor3f(1.0,0.5,0);
glBegin(GL_POLYGON);
glNormal3f( 0.10, 0.0, 0.0);
glVertex3f( -0.05 , 0, -0.02);
glVertex3f( 0.05 , 0, -0.02);
glVertex3f( 0.05 ,0, -0.06);
glVertex3f( -0.05 ,0, -0.06);
glEnd();
glEndList();
glEnable(GL_DEPTH_TEST);
glClearColor(0,0,0,1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 1.0 , 0.1, 60.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
$walls=drawwalls;
intro;
while(1){nav;}