#!/usr/bin/perl -w
use strict;
use OpenGL qw/ :all /;

use constant N_SHAPES => 7;

my @light0_position    = (2.0, 8.0, 2.0, 0.0);
my @light_diffuse      = (1.0, 1.0, 1.0, 1.0);
my @light_ambient      = (0.15, 0.15, 0.15, 0.15);
my @light_specular     = (1.0, 1.0, 1.0, 1.0);
my @mat_specular       = (1.0, 1.0, 1.0, 1.0);
my @mat_shininess      = (50.0);
my @mat_amb_diff_color = (0.5, 0.7, 0.5, 0.5);

my $spin = 0.0;


glutInit();
#glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowPosition (0, 0);
glutInitWindowSize(300, 300);
glutCreateWindow('test');
#glutFullScreen();
init();
glutReshapeFunc(\&resize);
glutDisplayFunc(\&display);
glutMouseFunc(\&mouse);
glutKeyboardFunc(\&keyboard);
#glutSpecialFunc(\&cbSpecialKeyPressed);
#glutVisibilityFunc(\&visibility);
glutIdleFunc(\&idle);
#glutPostRedisplay();

glutMainLoop();

sub DrawSphere
{
	my ($x, $y, $z, $radius, $pColor, $nsides) = @_;
	glMaterialfv_p(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, @$pColor);
#	glMaterialfv_p(GL_FRONT, GL_SPECULAR, @$pColor);
#	glMaterialfv_p(GL_FRONT, GL_EMISSION, @$pColor);
#	glMaterialfv_p(GL_FRONT, GL_SHININESS, 1.0);
	glPushMatrix();
		glTranslated($x, $y, -$z);
		glutSolidSphere($radius, $nsides, $nsides);
	glPopMatrix();
}

sub DrawCube
{
	my ($x, $y, $z, $size, $pColor) = @_;
	glMaterialfv_p(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, @$pColor);
	glPushMatrix();
		glTranslated($x, $y, $z);
		glutSolidCube($size);
	glPopMatrix();
}

sub DrawCylinder
{
	my ($x, $y, $z, $radius, $height, $pColor, $nsides) = @_;
	my $step = 6.28318530717958647692 / $nsides;

	glMaterialfv_p(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, @$pColor);
	glPushMatrix();
		glTranslated($x, $y, $z);
#上面
		glNormal3d(0.0, 1.0, 0.0);
		glBegin(GL_TRIANGLE_FAN);
		for(my $i = 0 ; $i < $nsides ; $i++) {
			my $t = $step * $i;
			glVertex3d($radius * sin($t), $height, $radius * cos($t));
		}
		glEnd();
#下面
		glNormal3d(0.0, -1.0, 0.0);
		glBegin(GL_TRIANGLE_FAN);
		for(my $i = 0 ; $i > -$nsides ; $i--) {
			my $t = $step * $i;
			glVertex3d($radius * sin($t), -$height, $radius * cos($t));
		}
		glEnd();
#側面
		glBegin(GL_QUAD_STRIP);
		for(my $i = 0 ; $i <= $nsides ; $i++) {
			my $t = $step * $i;
			my $xx = sin($t);
			my $zz = cos($t);
			glNormal3d($xx, 0.0, $zz);
			glVertex3f($radius * $xx,  $height, $radius * $zz);
			glVertex3f($radius * $xx, -$height, $radius * $zz);
		}
		glEnd();
	glPopMatrix();
}

sub DrawGround
{
	my ($height) = @_;

	my $ground = [
		[0.6, 0.6, 0.6, 1.0],
		[0.3, 0.3, 0.3, 1.0]
		];

	glBegin(GL_QUADS);
	glNormal3d(0.0, 1.0, 0.0);
	for(my $j = -5 ; $j < 5 ; $j++) {
		for(my $i = -5 ; $i < 5 ; $i++) {
			glMaterialfv_p(GL_FRONT, GL_DIFFUSE, @{$ground->[($i+$j) & 1]});
			glVertex3d($i,   $height, $j);
			glVertex3d($i,   $height, $j+1);
			glVertex3d($i+1, $height, $j+1);
			glVertex3d($i+1, $height, $j);
		}
	}
	glEnd();
}

sub errCallBack
{
	my ($errCode) = @_;
	my $estring = gluErrorString($errCode);
	print("Quadric Error: $estring\n");
	exit;
}

sub glDrawCylinder
{
	my ($radius, $height, $nsides) = @_;

	my $quad = gluNewQuadric();
#	gluQuadricCallback($quad, GLU_ERROR, \&errCallBack);
	gluQuadricDrawStyle($quad, GLU_FILL);
	gluQuadricNormals($quad, GLU_SMOOTH);

#シリンダー側面
	gluCylinder($quad, $radius, $radius, $height, $nsides, 1);
#上面
	glPushMatrix();
		glTranslated(0.0, 0.0, $height);
		gluDisk($quad, 0.0, $radius, $nsides, 1);
	glPopMatrix();
	
#下面
	gluQuadricOrientation($quad, GLU_INSIDE);
	gluDisk($quad, 0.0, $radius, $nsides, 1);

#qadlic objectの削除
	
	gluDeleteQuadric($quad);
}

sub display {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLightfv_p(GL_LIGHT0, GL_POSITION, @light0_position);
	glLightfv_p(GL_LIGHT0, GL_DIFFUSE,  @light_diffuse);
	glLightfv_p(GL_LIGHT0, GL_AMBIENT,  @light_ambient); 
	glLightfv_p(GL_LIGHT0, GL_SPECULAR, @light_specular);
	glLoadIdentity();
	gluLookAt(2.0, 4.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

#	&DrawGround(-0.1);
	&DrawSphere(1.3, 0.5, 0.5, 1.0, \@mat_amb_diff_color, 12);
#	&glDrawCylinder(0.3, 0.7, 12);
#	&DrawCube(0.5, 0.0, 0.0, 0.8, \@mat_amb_diff_color);
#	&DrawCylinder(0.5, 0.0, 0.0, 0.3, 0.7, \@mat_amb_diff_color, 12);

#	glMaterialfv_p(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, @mat_amb_diff_color);
#	glPushMatrix();
#		glScalef(2.0, 2.0, 2.0);
#		glRotatef($spin, 0.0, 1.0, 0.0);
#		glutSolidCube(1.0);
#		glutSolidSphere(2.0, 12, 1);
#		glutSolidCone(0.5, 0.8, 1, 1);
#		glutSolidDodecahedron();
#		glutSolidIcosahedron
#		glutSolidOctahedron
#		glutSolidTetrahedron
#		glutSolidTorus(0.3, 0.6, 2, 1);
#		glutSolidTeapot(1.0);
#		glutWireDodecahedron
#		glutWireIcosahedron
#		glutWireOctahedron
#		glutWireSphere
#		glutWireTeapot
#		glutWireTetrahedron
#		glutWireTorus
#	glPopMatrix();

	glutSwapBuffers();
}

sub resize
{
	my ($w, $h) = @_;
# $w, $h: 表示ウインドウのサイズが入ってくる

#表示するサイズ
	glViewport(0, 0, $w, $h);
#透視変換行列の設定
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(30.0, $h ? $w/$h : 0, 1.0, 100.0);

#モデルビュー変換行列の設定
	glMatrixMode(GL_MODELVIEW);
}

sub idle {
	$spin += 1.0;
	$spin = $spin - 360.0 if ($spin >360.0);
	glutPostRedisplay();
}

sub init {
  glClearColor(0.0, 0.0, 0.0, 1.0);
#For teapot
  glShadeModel(GL_SMOOTH);   
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);  
return;

#for noof
  glEnable(GL_LINE_SMOOTH);
  glShadeModel(GL_FLAT);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  for (my $i = 0; $i < N_SHAPES; $i++) {
    initshapes($i);
  }
  myReshape(200, 200);
}


sub keyboard
{
	my ($key, $x, $y) = @_;
print "keyboard ($key, $x, $y)\n";
#my $MtxModel;
#glGetDoublev_s(GL_MODELVIEW_MATRIX, $MtxModel);
#print "Model Matrix: ", @$MtxModel, "\n";

	if($key eq 'q' or $key eq 'Q' or $key == 113 or $key == 81) {
		exit;
	}
	else {
	}
}

sub mouse {
  my ($button, $state, $x, $y) = @_;
#x,y: 左上を(0,0)とした画面のピクセル座標
print "mouse ($x, $y)\n";

	if($button == GLUT_LEFT_BUTTON) {
		if($state == GLUT_DOWN) {
			glutIdleFunc(\&idle);
		}
		else {
			glutIdleFunc();
		}
	}
	elsif ($button == GLUT_RIGHT_BUTTON) {
		if($state == GLUT_DOWN) {
			glutPostRedisplay();
		}
	}
	else {
	}
}
