#!/usr/add-on/exptools_build/test_version/install/perl5/bin/perl
#
#       object oriented programming example
#
# Example developed entirely by Stan Melax (stan@arc.ab.ca).
# I wanted to try some object-oriented programming in perl,
# but I wanted to do something more real than just a "foo-bar" example :-)
# 
# I developed the smooth "chaseing" behavior used by the spaceship
# years ago in grad school for a VR assignment.  When Randy Pausch
# (a VR God from U of Virginia) visited the U of Alberta, he was
# impressed and took a copy of the algorithm.  
#

BEGIN{ unshift(@INC,"../blib"); }  # in case OpenGL is built but not installed
BEGIN{ unshift(@INC,"../blib/arch"); } # 5.002 gamma needs this
BEGIN{ unshift(@INC,"../blib/lib"); } # 5.002 gamma needs this
use OpenGL;

sub abs{
	(($_[0]>0)?$_[0]:-$_[0]);
}

$cow=1;
$plane=2;
$floor=3;
$enterprise=4;
sub initlists{
	glNewList($cow,GL_COMPILE);
	    glColor3f(1.0,0.0,0.0);
	    glBegin(GL_POLYGON);
	      glNormal3f(-1.0,   0.0,  0.0);
	      glVertex3f(-1.0 , -1.0, -1.0);
	      glVertex3f(-1.0 ,  1.0, -1.0);
	      glVertex3f(-1.0 ,  1.0,  1.0);
	      glVertex3f(-1.0 , -1.0,  1.0);
	    glEnd();
	    glColor3f(0.0,1.0,0.0);
	    glBegin(GL_POLYGON);
	      glNormal3f( 1.0,   0.0,  0.0);
	      glVertex3f( 1.0 , -1.0, -1.0);
	      glVertex3f( 1.0 ,  1.0, -1.0);
	      glVertex3f( 1.0 ,  1.0,  1.0);
	      glVertex3f( 1.0 , -1.0,  1.0);
	    glEnd();
	glEndList();

	glNewList($plane,GL_COMPILE);
	    glColor3f(0,0,0);
	    glBegin(GL_POLYGON);
	      glVertex3f( 1 ,  2,  1.0);
	      glVertex3f( 2 ,  1,  1.0);
	      glVertex3f( 2 ,  -1,  1.0);
	      glVertex3f( 1 ,  -2,  1.0);
	      glVertex3f( -1 ,  -2,  1.0);
	      glVertex3f( -2 ,  -1, 1.0);
	      glVertex3f( -2 ,  1,  1.0);
	      glVertex3f( -1 ,  2,  1.0);
	    glEnd();
	    glColor3f(1.0,0.0,1.0);
	    glBegin(GL_POLYGON);
	      glVertex3f( 1 ,  2,  3.0);
	      glVertex3f( 2 ,  1,  3.0);
	      glVertex3f( 2 ,  -1,  3.0);
	      glVertex3f( 1 ,  -2,  3.0);
	      glVertex3f( -1 ,  -2,  3.0);
	      glVertex3f( -2 ,  -1,  3.0);
	      glVertex3f( -2 ,  1,  3.0);
	      glVertex3f( -1 ,  2,  3.0);
	    glEnd();
	glEndList();

	glNewList($floor,GL_COMPILE);
	 for($i=0;$i<10;$i++) {
	  for($j=0;$j<10;$j++) {
	    $b = 1-sqrt(($i-4.5)*($i-4.5)+($j-4.5)*($j-4.5))/6.4;
	    glColor3f($b*0.5,(($i%2) ^ ($j%2) )?0.7*$b : 0 ,0);
	    glBegin(GL_POLYGON);
	      glVertex3f( (0+$i-5)*10 ,  (0+$j-5) *10,  0.0);
	      glVertex3f( (1+$i-5)*10 ,  (0+$j-5) *10,  0.0);
	      glVertex3f( (1+$i-5)*10 ,  (1+$j-5) *10,  0.0);
	      glVertex3f( (0+$i-5)*10 ,  (1+$j-5) *10,  0.0);
	    glEnd();
	  }
	 }
	glEndList();
}

sub readnff{
#  open(FILE,"</home/fholtry/public_html/plugin_test/spaceship.nff") || die "cant open spaceship.nff";
  $_="";
  while(!(/^82\s*$/)){$_=<DATA>;}
  $n=82;
  for($i=0;$i<$n;$i++) {
    $_=<DATA>;
    /(\S+)\s+(\S+)\s+(\S+)\s*$/ || die "couldn't parse file";
    ($x[$i],$y[$i],$z[$i])=($1,$2,$3);
  }
  $_=<DATA>;
  /^140/ || die "couldn't parse file";
  $p=140;
  glNewList($enterprise,GL_COMPILE);
  glScalef(0.02,0.02,0.02);
  glRotatef(90.0,0.0,0.0,1.0);
  glColor3f(0.0,1.0,1.0);
  for($i=0;$i<$p;$i++) {
    glBegin(GL_POLYGON);
    $_=<DATA>;
    /3\s+(\d+)\s+(\d+)\s+(\d+)\s/ || die "couldn't parse file";
    glVertex3f($x[$1],$y[$1],$z[$1]);
    glVertex3f($x[$2],$y[$2],$z[$2]);
    glVertex3f($x[$3],$y[$3],$z[$3]);
    glEnd();
  }
#  close(FILE);
  glEndList();
  $enterprise;
}

package A;

use OpenGL;
%defaults = (
	'name' => 'unnamed',
	'x' => 0 ,
	'y' => 0 ,
	'z' => 0 ,
	'dl'=> $main::plane,
);
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 {
}
sub draw {
	my $self=shift;
	glPushMatrix();
	glTranslatef($self->{'x'},$self->{'y'},$self->{'z'});
	glCallList($self->{'dl'});
	glPopMatrix ();
}


#------------------------------------------
package B;
@ISA=qw(A);

%defaults = (
	'dx',0,
	'dy',0,
	'dz',0,
);
sub new {
	my $type = shift;
	my $self = new A(%defaults,@_);
	push(@objects,$self);
	bless $self;
}

$WORLD_BOUNDARY =(20.0);
$WORLD_CEILING  =(10.0);
$WORLD_FLOOR    =(0.0);
sub move {
  my $self = shift;
  local($x,$y,$z,$dx,$dy,$dz)=
	(\$self->{'x'}, \$self->{'y'}, \$self->{'z'},
         \$self->{'dx'},\$self->{'dy'},\$self->{'dz'});
  $$x+=$$dx;
  $$y+=$$dy;
  $$z+=$$dz;
  # Bounce off Walls 
  ($$x>  $WORLD_BOUNDARY) && ($$dx= -abs($$dx));
  ($$x< -$WORLD_BOUNDARY) && ($$dx=  abs($$dx));
  ($$y>  $WORLD_BOUNDARY) && ($$dy= -abs($$dy));
  ($$y< -$WORLD_BOUNDARY) && ($$dy=  abs($$dy));
  ($$z>  $WORLD_CEILING ) && ($$dz= -abs($$dz));
  ($$z<  $WORLD_FLOOR   ) && ($$dz=  abs($$dz));
}


#------------------------------------------
package T;
@ISA=qw(B);
%defaults = (
	'name','target',
	'wait',0,
);
$damping = 0.99;
sub new {
	my $type = shift;
	my $self = new B(%defaults,@_);
	push(@objects,$self);
	bless $self;
}
sub move {
	my $self = shift;
	$self->{'dx'} *= $damping;
	$self->{'dy'} *= $damping;
	$self->{'wait'}-- if($self->{'wait'}>0) ;
	$self->B::move;
}
sub takeoff {
	my $self = shift;
	#print "takeoff\n";
	return if($self->{'wait'}>0) ;
	$self->{'dx'} = rand(2)-1.0;
	$self->{'dy'} = rand(2)-1.0;
	$self->{'wait'}=10;
}
#------------------------------------------
package C;
@ISA=qw(B);
use OpenGL;

%defaults = (
	'target' => 0,
	'h' => 0,
	'dh' => 0,
);
sub new {
	my $type = shift;
	my $self = new B(%defaults,@_);
	push(@objects,$self);
	bless $self;
}
$DAMPING 	= (0.98);
$ACCELLERATION 	= (0.01);
$BANK_DAMPING 	= (0.8);
sub move{
  	my $self = shift;
  	local($x,$y,$z,$dx,$dy,$dz,$h,$dh)=
		(\$self->{'x'}, \$self->{'y'}, \$self->{'z'},
        	 \$self->{'dx'},\$self->{'dy'},\$self->{'dz'},
		 \$self->{'h'},\$self->{'dh'});
	local $t  = $self->{'target'};
	($t) || die "No Target\n"; 
	local ($tx,$ty) = ($t->{'x'},$t->{'y'});
	
   	local $theading = atan2($ty-$$y,$tx-$$x);
	local $speed = sqrt($$dx*$$dx+$$dy*$$dy);
	$$h = ($$dy==0.0&&$$dx==0.0)? $$h : atan2($$dy,$$dx);
	$tdheading = $theading-$$h;
	while($tdheading > 3.14){ $tdheading -= 2*3.14};
	while($tdheading <-3.14){ $tdheading += 2*3.14};
	$$dh*= $BANK_DAMPING; 
	$$dh += $tdheading* 0.01;
	$$h += $$dh;
	if($tdheading <3.14/6 && $tdheading>-3.14/6 ) {
		$speed += $ACCELLERATION;
	}
    	elsif ($tdheading <3.14/3 && $tdheading>-3.14/3 ) {
		$speed += $ACCELLERATION/4;
	}
	$$dx = cos($$h)*$speed;
	$$dy = sin($$h)*$speed;
	#if( (t%10==0) && tdheading <3.14/6 && tdheading>-3.14/6 ){
	#	# fire();
	#}
	# damping 
	$$dx *= $DAMPING;
	$$dy *= $DAMPING;
	$$dz *= $DAMPING;
	#$self->B::move;
  	$$x+=$$dx;
  	$$y+=$$dy;
  	$$z+=$$dz;
	$t->takeoff if($$x > $tx-5 && $$x < $tx+5  &&
	   $$y > $ty-5 && $$y < $ty+5 );
}

sub draw {
	my $self=shift;
	glPushMatrix();
	glTranslatef($self->{'x'},$self->{'y'},$self->{'z'});
	glRotatef($self->{'h'}*180/3.14, 0.0,0.0,1.0);
	glRotatef(-60.0 * $self->{'dh'}/(1.0/(1.0-0.8)*0.01*3.14), 1.0, 0.0, 0.0);
	glCallList($self->{'dl'});
	glPopMatrix ();
}

#------------------------------------------
package main;


glpOpenWindow(parent,$Plugin::brinfo{xwindow_id},width,400,height,400,
	      mask => StructureNotifyMask|KeyPressMask,
	      attributes=>[GLX_RGBA,GLX_DOUBLEBUFFER]);
glShadeModel (GL_FLAT);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 500.0); 
glMatrixMode(GL_MODELVIEW);


initlists;
glColor3f(1,0,0);
glClearColor(0,0,0.3,1);

new A('dl'=>$floor,'name'=>'the happy floor');
#$a = new A( 'y' => 0.2,  'name' => 'useless dude');
$b = new T( 'x' => 10, 'dx'=> 0.4,  'name' => 'bad dude');
readnff;
$c = new C('z' => 5,'dl'=>$enterprise, 'x' => -10, 'target'=>$b, 'name' => 'killer');
$w=100.0;$t= time;$p= $t-1;
$rin=$win=$ein='';
$spf = 1;
$spin=0;

$cb{&ConfigureNotify} = sub { local($e,$w,$h)=@_;glViewport(0,0,$w,$h);
                         # print "viewport $w,$h\n";
                        };
$cb{&KeyPress} = sub { # print "@_[1] ",ord(@_[1])," keypress @_\n";
                      local($ss); &$ss(@_[1]) if ($ss=$kcb{@_[1]}); };
$kcb{'q'} = $kcb{'Q'} = $kcb{"\033"} = sub{ print "Good-Bye\n"; exit 0;};
sub setspeed{$C::ACCELLERATION =  $_[0]/100;}
foreach $i (0..9){
        $kcb{"$i"}=\&setspeed;
}


while(1){
	$spf = ($spf*$w + $t-$p) /($w+1.0); 
	$fps = ($spf)?1.0/$spf:0;
	$p=$t;
	$t= time;

	while($p=XPending) {
		@e=&glpXNextEvent;
		&$s(@e) if($s=$cb{$e[0]});
        }


	vec($rin,0,1) = 1;
	if(select($rout=$rin,undef,undef,0)) {
		$_=<> || die "End Of File";
		eval;
	}
	foreach $x (@A::objects) {
		$x->move;
		#$x->print;
	}
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	glLoadIdentity ();

	# set the viewpoint
	glTranslatef (0.0, 0.0, -30.0);    
	glRotatef(-45.0, 1.0,0.0,0.0);
	$spin += 1;
	glRotatef($spin, 0.0,0.0,1.0);
	
	foreach $x (@A::objects) {
		$x->draw;
	}
	glFlush();
	glXSwapBuffers;
}


__END__
nff
version 2.00
viewpos  0.000000 0.000000 0.000000
viewdir  0.000000 0.000000 1.000000

SPACESHIP
82
-60.000000 50.000004 10.508476
-20.000000 50.000000 -9.830511
-20.000000 60.000000 -9.830509
-60.000000 60.000004 10.508476
-60.000000 50.000004 0.508473
-20.000000 50.000000 -19.830513
-20.000000 60.000000 -19.830509
-60.000000 60.000004 0.508474
20.000000 50.000000 -9.836067
60.000000 50.000004 10.491802
60.000000 60.000004 10.491802
20.000000 60.000000 -9.836065
20.000000 50.000000 -19.836069
60.000000 50.000004 0.491801
60.000000 60.000004 0.491802
20.000000 60.000000 -19.836065
-70.000000 20.000000 10.000005
-60.000000 20.000000 10.000005
-60.000000 120.000000 9.999995
-70.000000 120.000000 9.999995
-70.000000 20.000000 0.000005
-60.000000 20.000000 0.000005
-60.000000 120.000000 -0.000005
-70.000000 120.000000 -0.000005
60.000000 20.000000 10.000005
70.000000 20.000000 10.000005
70.000000 120.000000 9.999995
60.000000 120.000000 9.999995
60.000000 20.000000 0.000005
70.000000 20.000000 0.000005
70.000000 120.000000 -0.000005
60.000000 120.000000 -0.000005
-20.000000 0.000001 -9.999996
20.000000 0.000001 -9.999996
20.000000 90.000000 -10.000004
-20.000000 90.000000 -10.000004
-20.000000 -0.000001 -39.999996
20.000000 -0.000001 -39.999996
20.000000 90.000000 -40.000004
-20.000000 90.000000 -40.000004
0.000000 -50.000000 0.000005
0.000000 -50.000000 10.000005
-15.450733 -2.447136 0.000001
-15.450733 -2.447135 10.000001
-29.389170 -9.549080 0.000001
-29.389170 -9.549080 10.000001
-40.450787 -20.610649 0.000002
-40.450787 -20.610649 10.000002
-47.552795 -34.549053 0.000004
-47.552795 -34.549053 10.000004
-50.000000 -49.999901 0.000005
-50.000000 -49.999901 10.000005
-47.552853 -65.450768 0.000006
-47.552853 -65.450768 10.000006
-40.450897 -79.389198 0.000007
-40.450897 -79.389198 10.000008
-29.389326 -90.450806 0.000008
-29.389326 -90.450806 10.000009
-15.450917 -97.552803 0.000008
-15.450917 -97.552803 10.000009
-0.000065 -100.000000 0.000010
-0.000065 -100.000000 10.000010
15.450794 -97.552841 0.000008
15.450794 -97.552841 10.000009
29.389221 -90.450882 0.000008
29.389221 -90.450882 10.000009
40.450825 -79.389297 0.000007
40.450825 -79.389297 10.000008
47.552814 -65.450890 0.000006
47.552814 -65.450890 10.000006
50.000000 -50.000031 0.000005
50.000000 -50.000031 10.000005
47.552834 -34.549175 0.000004
47.552834 -34.549175 10.000004
40.450863 -20.610752 0.000002
40.450863 -20.610752 10.000002
29.389273 -9.549156 0.000001
29.389273 -9.549156 10.000001
0.000001 0.000000 0.000000
15.450856 -2.447175 0.000001
15.450856 -2.447174 10.000001
0.000001 0.000000 10.000000
140
3 81 80 79 0xf00 both
3 81 79 78 0xf00 both
3 80 77 76 0xf00 both
3 80 76 79 0xf00 both
3 77 75 74 0xf00 both
3 77 74 76 0xf00 both
3 75 73 72 0xf00 both
3 75 72 74 0xf00 both
3 73 71 70 0xf00 both
3 73 70 72 0xf00 both
3 71 69 68 0xf00 both
3 71 68 70 0xf00 both
3 69 67 66 0xf00 both
3 69 66 68 0xf00 both
3 67 65 64 0xf00 both
3 67 64 66 0xf00 both
3 65 63 62 0xf00 both
3 65 62 64 0xf00 both
3 63 61 60 0xf00 both
3 63 60 62 0xf00 both
3 61 59 58 0xf00 both
3 61 58 60 0xf00 both
3 59 57 56 0xf00 both
3 59 56 58 0xf00 both
3 57 55 54 0xf00 both
3 57 54 56 0xf00 both
3 55 53 52 0xf00 both
3 55 52 54 0xf00 both
3 53 51 50 0xf00 both
3 53 50 52 0xf00 both
3 51 49 48 0xf00 both
3 51 48 50 0xf00 both
3 49 47 46 0xf00 both
3 49 46 48 0xf00 both
3 47 45 44 0xf00 both
3 47 44 46 0xf00 both
3 45 43 42 0xf00 both
3 45 42 44 0xf00 both
3 43 81 78 0xf00 both
3 43 78 42 0xf00 both
3 80 81 41 0xf00 both
3 77 80 41 0xf00 both
3 75 77 41 0xf00 both
3 73 75 41 0xf00 both
3 71 73 41 0xf00 both
3 69 71 41 0xf00 both
3 67 69 41 0xf00 both
3 65 67 41 0xf00 both
3 63 65 41 0xf00 both
3 61 63 41 0xf00 both
3 59 61 41 0xf00 both
3 57 59 41 0xf00 both
3 55 57 41 0xf00 both
3 53 55 41 0xf00 both
3 51 53 41 0xf00 both
3 49 51 41 0xf00 both
3 47 49 41 0xf00 both
3 45 47 41 0xf00 both
3 43 45 41 0xf00 both
3 81 43 41 0xf00 both
3 78 79 40 0xf00 both
3 79 76 40 0xf00 both
3 76 74 40 0xf00 both
3 74 72 40 0xf00 both
3 72 70 40 0xf00 both
3 70 68 40 0xf00 both
3 68 66 40 0xf00 both
3 66 64 40 0xf00 both
3 64 62 40 0xf00 both
3 62 60 40 0xf00 both
3 60 58 40 0xf00 both
3 58 56 40 0xf00 both
3 56 54 40 0xf00 both
3 54 52 40 0xf00 both
3 52 50 40 0xf00 both
3 50 48 40 0xf00 both
3 48 46 40 0xf00 both
3 46 44 40 0xf00 both
3 44 42 40 0xf00 both
3 42 78 40 0xf00 both
3 39 38 37 0xff0 both
3 39 37 36 0xff0 both
3 39 35 34 0xff0 both
3 39 34 38 0xff0 both
3 38 34 33 0xff0 both
3 38 33 37 0xff0 both
3 37 33 32 0xff0 both
3 37 32 36 0xff0 both
3 36 32 35 0xff0 both
3 36 35 39 0xff0 both
3 35 32 33 0xff0 both
3 35 33 34 0xff0 both
3 31 30 29 0x0f0 both
3 31 29 28 0x0f0 both
3 31 27 26 0x0f0 both
3 31 26 30 0x0f0 both
3 30 26 25 0x0f0 both
3 30 25 29 0x0f0 both
3 29 25 24 0x0f0 both
3 29 24 28 0x0f0 both
3 28 24 27 0x0f0 both
3 28 27 31 0x0f0 both
3 27 24 25 0x0f0 both
3 27 25 26 0x0f0 both
3 23 22 21 0x0ff both
3 23 21 20 0x0ff both
3 23 19 18 0x0ff both
3 23 18 22 0x0ff both
3 22 18 17 0x0ff both
3 22 17 21 0x0ff both
3 21 17 16 0x0ff both
3 21 16 20 0x0ff both
3 20 16 19 0x0ff both
3 20 19 23 0x0ff both
3 19 16 17 0x0ff both
3 19 17 18 0x0ff both
3 15 14 13 0x00f both
3 15 13 12 0x00f both
3 15 11 10 0x00f both
3 15 10 14 0x00f both
3 14 10 9 0x00f both
3 14 9 13 0x00f both
3 13 9 8 0x00f both
3 13 8 12 0x00f both
3 12 8 11 0x00f both
3 12 11 15 0x00f both
3 11 8 9 0x00f both
3 11 9 10 0x00f both
3 7 6 5 0xf0f both
3 7 5 4 0xf0f both
3 7 3 2 0xf0f both
3 7 2 6 0xf0f both
3 6 2 1 0xf0f both
3 6 1 5 0xf0f both
3 5 1 0 0xf0f both
3 5 0 4 0xf0f both
3 4 0 3 0xf0f both
3 4 3 7 0xf0f both
3 3 0 1 0xf0f both
3 3 1 2 0xf0f both
