#!/usr/bin/perl -w

use strict;
use OpenGL qw/ :all /;

use lib 'd:/Programs/Perl/lib';
use Graphics::OpenGL;
use Crystal::OpenGL;
use Crystal::CIF;
use Crystal::Crystal;

my $CIFPath = "D:/Programs/Perl/lib/Crystal/BaTiO3.cif";
#my $CIFPath = "D:/MyWebs/Research/CrystalStructure/BaTiO3.cif"; #Si2.cif";
my ($WindowWidth, $WindowHeight) = (300, 300);
my $SaveImagePath = 'g:/MyImage.tga';

my $r = 0; #回転角
#my $spin = 0.0;
my $Light0 = new Graphics::OpenGLMaterial(
				-Position => [2.0, 8.0, 2.0, 0.0],
				-Diffuse  => [1.0, 1.0, 1.0, 1.0],
				-Ambient  => [0.15, 0.15, 0.15, 0.15],
				-Specular => [1.0, 1.0, 1.0, 1.0],
			);
my $Light1 = new Graphics::OpenGLMaterial(
				-Position => [-2.0, -8.0, 2.0, 0.0],
				-Diffuse  => [1.0, 1.0, 1.0, 1.0],
				-Ambient  => [0.15, 0.15, 0.15, 0.15],
				-Specular => [1.0, 1.0, 1.0, 1.0],
			);
my $Mater1 = new Graphics::OpenGLMaterial(
				-Diffuse   => [0.5, 0.7, 0.5, 0.5],
				-Ambient   => [0.5, 0.7, 0.5, 0.5],
				-Specular  => [1.0, 1.0, 1.0, 1.0],
#				-Emission  => [0.0, 0.0, 1.0, 1.0],
				-Shininess => [50.0],
			);
my $IonRadiusScaleFactor = 0.6;
my $MaxBondLength        = 2.6;
my $nMaxBonds            = 1000;
#my ($nx, $ny, $nz)       = (1, 1, 1);
my ($nx, $ny, $nz)       = (1.5, 1.1, 1.1);
#my ($nx, $ny, $nz)       = (2, 2, 2);

my $Crystal = &ReadCIFFile($CIFPath);
&Draw($Crystal, $nx, $ny, $nz, $MaxBondLength, $nMaxBonds, $IonRadiusScaleFactor);

exit;

#==================================================================
#
#==================================================================
sub Draw
{
	my ($Crystal, $nx, $ny, $nz, $MaxBondLength, $nMaxBonds, $IonRadiusScaleFactor) = @_;

	my $OGL = new Graphics::OpenGL();
	$OGL->Initialize(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH, 0, 0, $WindowWidth, $WindowHeight, 'Test Module');
	&InitializeOpenGL($OGL);
	$OGL->SetFunctions(
			-Reshape    => sub { &resize($OGL, @_); },
			-Display    => sub { &display($OGL, $Crystal, $nx, $ny, $nz,
									$MaxBondLength, $nMaxBonds, $IonRadiusScaleFactor, @_); },
			-Mouse      => sub { &mouse($OGL, @_); },
			-Keyboard   => sub { &keyboard($OGL, @_); },
#			-Special    => sub { &cbSpecialKeyPressed($OGL, @_); },
#			-Visibility => sub { &visibility($OGL, @_); },
			-Idel       => sub { &idle($OGL, @_); },
		);
#	glutPostRedisplay();

my $MenuTest = 0;
if($MenuTest) {
	my $iMenu = glutCreateMenu(sub { &menu($OGL, @_); });
	glutAddMenuEntry("Menu1", 1);
	glutAddSubMenu("Menu2", $iMenu);
	glutAttachMenu(GLUT_LEFT_BUTTON | GLUT_RIGHT_BUTTON);
}

my $TimerTest = 0;
if($TimerTest) {
	$OGL->SetFunctions(
			-Timer     => sub { &timer($OGL, @_); },
			-DelayTime => 1000,
			-svalue    => 1,
		);
}

	$OGL->Run();
}

sub menu
{
	my ($OGL, $isel, @a) = @_;
print "menu, $isel\n";
}

sub timer
{
	my ($OGL, $svalue, @a) = @_;
print "timer, $svalue\n";
	$OGL->SetFunctions(
			-Timer    => sub { &timer($OGL, @_); },
			-DelayTime => 1000,
			-svalue    => 1,
		);
}

sub ReadCIFFile
{
	my ($CIFFile) = @_;

	my $CIF = new CIF();
	my $Crystal = new Crystal();
	unless($CIF->Read($CIFFile)) {
		print "aError: Can not read $CIFFile.\n";
		exit;
	}
	$Crystal = $CIF->GetCCrystal();
	$Crystal->ExpandCoordinates();
	return $Crystal;
}

sub InitializeOpenGL {
	my ($OGL) = @_;

	$OGL->ClearColor(0.0, 0.0, 0.0, 1.0);
#For teapot
	$OGL->ShadeModel(GL_SMOOTH);
	$OGL->Enable(GL_DEPTH_TEST, GL_LIGHTING, GL_LIGHT0);
}

sub display {
	my ($OGL, $Crystal, $nx, $ny, $nz, $MaxBondLength, $nMaxBonds, $rScale,) = @_;
print "display: r=$r\n";
	$OGL->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	$OGL->SetLight(GL_LIGHT0, $Light0);
#	$OGL->SetLight(GL_LIGHT1, $Light1);
	$OGL->InitializeMatrix();
	$OGL->LookAt(12.0, 5.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	glRotated($r, 0.0, 1.0, 0.0);

	my $COGL = new Crystal::OpenGL();
	$COGL->SetSampleName($Crystal->CrystalName());

	$COGL->Draw($OGL, $Crystal, $nx, $ny, $nz, $MaxBondLength, $nMaxBonds, $rScale);

	$OGL->Show();

	if(++$r >= 360) { 
		$r = 0;
	}
}

sub resize
{
	my ($OGL, $w, $h) = @_;

	$OGL->Viewport(0, 0, $w, $h);
#透視変換行列の設定
	$OGL->MatrixMode(GL_PROJECTION);
	$OGL->InitializeMatrix();
	$OGL->Perspective(60.0, $h ? $w/$h : 0, 1.0, 100.0);
#モデルビュー変換行列の設定
	$OGL->MatrixMode(GL_MODELVIEW);
}

sub idle {
	my ($OGL) = @_;

#	$spin += 1.0;
#	$spin = $spin - 360.0 if ($spin >360.0);
	$OGL->PostRedisplay();
}

sub mouse {
  my ($OGL, $button, $state, $x, $y, $HitTest) = @_;
  $HitTest = 0 if(!defined $HitTest);

print "mouse ($x, $y)\n";

my $SaveTest = 1;
if($SaveTest) {
use OpenGL::Image;
my $image = new OpenGL::Image(width => $WindowWidth, height => $WindowHeight);
#my $image = new OpenGL::Image(engine=>'Magick', width => $WindowWidth, height => $WindowHeight);
glReadPixels_c(0, 0, $WindowWidth, $WindowHeight, GL_RGBA, GL_UNSIGNED_BYTE, $image->Ptr());
$image->Save($SaveImagePath);
}

#my $HitTest = 1;
if($HitTest) {
my @buffer;
#glSelectBuffer_c(100, \@buffer);
glRenderMode(GL_SELECT);
glMatrixMode(GL_PROJECTION);
glInitNames();
glPushName(-1);
glPushMatrix();
glLoadIdentity();
my @viewport = glGetIntegerv_p(GL_VIEWPORT);
my ($cx, $cy, $dx, $dy) = (50, 50, 5, 5);
gluPickMatrix_p($cx, $cy, $dx, $dy, @viewport);
#gluPerspective(...)
glMatrixMode(GL_MODELVIEW);
#通常の描画
glLoadName(1);
#オブジェクト1を描画...
glRotated($r, 0.0, 1.0, 0.0);
my $COGL = new Crystal::OpenGL();
$COGL->Draw($OGL, $Crystal, 1,1,1,2.6,1000,0.3);

glMatrixMode(GL_PROJECTION);
glPopMatrix();
my $hits = glRenderMode(GL_RENDER);
print "hit: $hits \n";
my @model = glGetDoublev_p(GL_MODELVIEW_MATRIX); #\@model);
my @proj  = glGetDoublev_p(GL_PROJECTION_MATRIX); #\@model);
print "model=", @model, @proj, "\n";
my $windowh = 100;
my ($x, $y) = (50, 50);
my $z = glReadPixels_p($x, $windowh - $y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT);
print "z=$z\n";
$z = -2.0;
#my ($ox, $oy, $oz) = gluUnProject_p($x, $windowh-$y, $z, @model, @proj, @viewport);
#print "o=$ox, $oy, $oz\n";
my $a = gluUnProject_p($x, $windowh-$y, $z, @model, @proj, @viewport);
print "o=$a\n";

	&mouse($OGL, $button, $state, $x, $y, 0);
}

	if($button == GLUT_LEFT_BUTTON) {
		if($state == GLUT_DOWN) {
			$OGL->SetFunctions(-Idle => sub { &idle($OGL, @_); } );
#			$OGL->SetFunctions(-Mouse => sub { &mouse($OGL, @_); } );
		}
		else {
#			glutIdleFunc();
			$OGL->SetFunctions(-Idle => '');
#			$OGL->SetFunctions(-Mouse => '');
		}
	}
	elsif ($button == GLUT_RIGHT_BUTTON) {
		if($state == GLUT_DOWN) {
			$OGL->PostRedisplay();
		}
	}
	else {
	}
}
