#!/usr/bin/perl -w

use OpenGL ":old",":glutfunctions",":gluconstants",":functions";
use Time::HiRes qw (gettimeofday tv_interval usleep);
use strict;
    # because of the OpenGL header functs
no strict "subs";
our (@tri3d,@options,$z,$t,$time,$fps,$xmin,$xmax,$ymin,$ymax,$zmin,$zmax,$tmin,$tmax,$xres,$yres,$zres,$tres,$width,$height);



$xmin = -10;
$xmax = 10;
$ymin = -100;
$ymax = 100;
$zmin = -100;
$zmax = 100;
$tmin = -100;
$tmax = 100;

#Anzahl Punkte
$xres = 100;
$yres = 100;
$zres = 100;
$tres = 100;

$z = $zmin;
$t = $tmin;

$time = [gettimeofday];
$fps = 5;

# 0(1): 2d
# 0(2): 3d wire
# 0(3): 3d solid
# 1(0): stable
# 1(1): time-function
# 2(0): orthographic viewing
# 2(1): perspective viewing
# 2(2): stereo viewing
# 2(3): 2nd way of stereo viewing

@options = (1,0,0);

init();
    # main loop
glutMainLoop;


#- eval error
#- perldoc -f eval

sub init{
    glutInit(@ARGV);
    glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(600, 600);
    glutInitWindowPosition(50, 50);
    glutCreateWindow("graph window");

    # black
    glClearColor(0,0,0,0);
    # reset
#    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    # set the window properties
    glOrtho($xmin,$xmax,$ymin,$ymax,$zmin,$zmax);

    idle();        
    glFlush();

    glutKeyboardFunc(\&keyboard);
    glutDisplayFunc(\&display);
    glutReshapeFunc(\&resize);
    glutIdleFunc(\&idle);
}



sub idle {
    our (@tripar,$x,$y,$j);

    if (($options[1] == 0) and ($z<$zmax)) {

    for ($j=0; $j<=(3*$xres-3); $j=$j+3) {

        $y=$x*$z/20;
    
        $tripar[$j]=$x;
        $tripar[$j+1]=$y;
        $tripar[$j+2]=$z;
        $x += ($xmax-$xmin)/($xres-1);
    }
    $x=$xmin;
    $j = 0;
#    if ($z<$zmax) { $z += ($zmax-$zmin)/($zres-1);}
    $z += ($zmax-$zmin)/($zres-1);
    if (tv_interval($time)<(1/$fps)) {
	usleep (1/120);
	return;
    }
    $time = [gettimeofday];

#    splice(@tri3d,($#tri3d-$#tripar+1));
    splice(@tri3d,($#tripar+1));
    unshift(@tri3d,@tripar);

    display();
    }

}

sub display {
    glColor3f(1,1,1);
    glClear(GL_COLOR_BUFFER_BIT);
    my $i;

    # display2d()
    if ($options[0] == 0) {
    }
    
    # display3d_wire()
    elsif ($options[0] == 1) {
	glBegin(GL_LINE_STRIP);
	{
	    # jeweils um einen Punkt springen
	    for ($i=0; $i<=(3*$xres-7); $i=$i+3) {
		glVertex3f($tri3d[$i],$tri3d[$i+1],$tri3d[$i+2]);
		glVertex3f($tri3d[$i+3*$xres+1],$tri3d[$i+3*$xres+2],$tri3d[$i+3*$xres+3]);
		glVertex3f($tri3d[$i+3*$xres+4],$tri3d[$i+3*$xres+5],$tri3d[$i+3*$xres+6]);
		glVertex3f($tri3d[$i+3],$tri3d[$i+4],$tri3d[$i+5]);
	    }
	} glEnd();
    }
    
    # display3d_solid()
    # FALSCH
    elsif ($options[0] == 2) {
	glBegin(GL_TRIANGLES);
	{
	    for $i (0..($xres*3-4)) {
		glVertex3f($tri3d[$i],$tri3d[$i+1],$tri3d[$i+2]);
		glVertex3f($tri3d[$i+3],$tri3d[$i+4],$tri3d[$i+5]);
		glVertex3f($tri3d[$i+3*$xres],$tri3d[$i+3*$xres+1],$tri3d[$i+3*$xres+2]);
	    }
	} glEnd();
    }
    
    glFlush();
    glutSwapBuffers();    
}


sub keyboard {
    my ($key) = @_;
    $key = chr($key);
    if($key=~/w/i){
    # rotate up
	glRotatef(6.0, 1, 0, 0.0);
    }elsif($key=~/s/i){
    # rotate down
        glRotatef(-6.0, 1, 0, 0.0);
    }elsif($key=~/a/i){
    # rotate left
        glRotatef(6.0, 0.0, 1, 0);
    }elsif($key=~/d/i){
    # rotate right
        glRotatef(-6.0, 0.0, 1, 0);
    }elsif($key=~/q/i){
        exit();
    }elsif($key=~/m/i){
        screenshot();
    }elsif($key=~/r/i){
        glScalef(1.1,1.1,1.1);
    }elsif($key=~/f/i){
        glScalef(0.9,0.9,0.9);
    }
    
    # repaint the window
    display(); 
}


sub resize{
    ($width,$height)=@_;
}


sub getheader{
    my ($width,$height) = @_;
    my ($header);

    $header =  pack("s",hex("4d42"));	        #signature
    $header .= pack("i",$width*$height*3+hex(36));#size (inc header)
    $header .= pack("s",0);			#reserved
    $header .= pack("s",0);			#reserved
    $header .= pack("i",hex(36));		#offset
    $header .= pack("i",40);		        #size of BITMAPINFOHEADER structure, must be 40
    $header .= pack("i",$width);		#width
    $header .= pack("i",$height);		#hight
    $header .= pack("s",1);			#number of planes in the image, must be 1
    $header .= pack("s",24);	                #bites per pixel
    $header .= pack("i",0);			#compression type (0=none, 1=RLE-8, 2=RLE-4)
    $header .= pack("i",$width*$height*3);	#size of image data
    $header .= pack("i",0);			#horizontal resolution in pixels per meter (unreliable)
    $header .= pack("i",0);			#vertical resolution in pixels per meter (unreliable)
    $header .= pack("i",0);			#number of colors in image, or zero
    $header .= pack("i",0);			#number of important colors, or zero

    return $header;
}


sub screenshot {
    my $num = 1;
    my $i;
    $num++ while(-f "image$num.bmp");

    if(open(IMAGE,">image$num.bmp")){
        print IMAGE getheader($width,$height);
        my @pixels=glReadPixels_p(0, 0,$width,$height, GL_RGB,GL_UNSIGNED_INT);
        #{print (IMAGE pack("B*", $i )); }for $i (@pixels);
        for $i (0..(($#pixels-1)/3)){
            my ($red, $green, $blue) = ($pixels[$i*3],$pixels[$i*3+1],$pixels[$i*3+2]);
            print IMAGE pack("B B B",$blue,$green,$red);
        }
        #for $pixel (@pixels){ print IMAGE pack ("B*",$pixel);}
        close(IMAGE);
    }
}


sub reset {
    $z = $zmin;
    $t = $tmin;
    glClearColor(0,0,0,0);
    glLoadIdentity();
    display();
}