#!/usr/bin/perl -w

use strict;
use OpenGL qw/ :all /;

use lib 'd:/Programs/Perl/lib';
use Sci qw(mod);
use Graphics::OpenGL;

#/* オブジェクトの数 */
my $nObjects = 5;
my ($WindowWidth, $WindowHeight) = (300, 300);
#/* 各オブジェクトの色 */
my $gray = [ 0.7, 0.7, 0.7, 1.0 ];
my $blue = [ 0.1, 0.1, 0.9, 1.0 ];
my @material;

my $OGL = new Graphics::OpenGL();
$OGL->OnInitializeForMouseTranslation();
$OGL->OnInitializeForMouseRotation();
$OGL->OnInitializeForMouseZoom(10.0, 30.0);
$OGL->{KeyMouseMode} = 'rot';

$OGL->Initialize(GLUT_RGBA | GLUT_DEPTH, 0, 0, $WindowWidth, $WindowHeight, 'Test');
$OGL->SetFunctions(
		-Reshape    => sub { &resize($OGL, @_);   },
		-Display    => sub { &display($OGL, @_);  },
		-Mouse      => sub { &mouse($OGL, @_);    },
		-Motion     => sub { &motion($OGL, @_);   },
		-Keyboard   => sub { &keyboard($OGL, @_); },
		);
&InitializeOpenGL($OGL);
&scene($OGL);
$OGL->Run();

exit;

sub keyboard
{
	my ($OGL, $key, $x, $y) = @_;

	if($key == unpack('c', 'q') or $key == unpack('c', 'Q')) {
		exit;
	}
	elsif($key == unpack('c', 'c') or $key == unpack('c', 'C')) {
		if($OGL->{KeyMouseMode} eq 'zoom') {
			$OGL->{KeyMouseMode} = 'rot';
			print "Mouse mode changed to 'rotation'.\n";
		}
		else {
			$OGL->{KeyMouseMode} = 'zoom';
			print "Mouse mode changed to 'zoom'.\n";
		}
	}
}

sub motion {
	my ($OGL, $x, $y) = @_;

	if($OGL->{MouseMode} eq 'rot') {
		if($OGL->{KeyMouseMode} eq 'zoom') {
			$OGL->OnMotionForMouseZoom($x, $y);
		}
		else {
			$OGL->OnMotionForMouseRotation($x, $y);
		}
	}
	elsif($OGL->{MouseMode} eq 'tr') {
		$OGL->OnMotionForMouseTranslation($x, $y);
	}
}

sub mouse {
	my ($OGL, $button, $state, $x, $y) = @_;

	if($button == GLUT_LEFT_BUTTON) {
		if($state == GLUT_DOWN) {
			if($OGL->{KeyMouseMode} eq 'zoom') {
				$OGL->OnMouseDownForMouseZoom($x, $y);
			}
			else {
				$OGL->OnMouseDownForMouseRotation($x, $y);
			}
			$OGL->{MouseMode} = 'rot';
		}
		elsif($state == GLUT_UP) {
			if($OGL->{KeyMouseMode} eq 'zoom') {
				$OGL->OnMouseUpForMouseZoom($x, $y);
			}
			else {
				$OGL->OnMouseUpForMouseRotation($x, $y);
			}
			$OGL->{MouseMode} = '';
		}
	}
	elsif($button == GLUT_RIGHT_BUTTON) {
		if($state == GLUT_DOWN) {
			$OGL->OnMouseDownForMouseTranslation($x, $y);
			$OGL->{MouseMode} = 'tr';
		}
		elsif($state == GLUT_UP) {
			$OGL->OnMouseUpForMouseTranslation($x, $y);
			$OGL->{MouseMode} = '';
		}
	}
	$OGL->Redraw();
}

sub resize
{
	my ($OGL, $w, $h) = @_;

#  /* ウィンドウ全体をビューポートにする */
	$OGL->Viewport(0, 0, $w, $h);

#  /* 透視変換行列を設定する */
#	$OGL->MatrixMode(GL_PROJECTION);
#	$OGL->InitializeMatrix();
#	$OGL->Perspective(30.0, $w / $h, 1.0, 100.0);
	$OGL->OnResizeForMouseZoom($w, $h);
	$OGL->OnResizeForMouseTranslation($w, $h);
	$OGL->OnResizeForMouseRotation($w, $h);

#  /* モデルビュー変換行列を指定しておく */
	$OGL->MatrixMode(GL_MODELVIEW);
}

sub scene
{
	my ($OGL) = @_;

	my $width  = 4.0;
	my $center = $width / 2.0;
	my $step   = $width / ($nObjects - 1);
	for (my $i = 0; $i < $nObjects ; $i++) {
		$OGL->SetMaterial($material[$i], GL_FRONT);
		$OGL->DrawSphere($i * $step - $center, (($i & 1) * 2 - 1) * $step, 0.0, 0.5, undef, 10);
	}
}

sub display {
	my ($OGL) = @_;

	$OGL->OnDisplayForMouseTranslation();
	$OGL->OnDisplayForMouseRotation();

	$OGL->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
#	$OGL->LookAt(0.0, 0.0, -10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	$OGL->OnDisplayForMouseZoom();

	$OGL->PushMatrix();
	$OGL->OnDrawForMouseZoom();
	$OGL->OnDrawForMouseTranslation();
	$OGL->OnDrawForMouseRotation();
	&scene($OGL);
	$OGL->PopMatrix();

	$OGL->Flush();
}

sub InitializeOpenGL
{
	my ($OGL) = @_;

	$OGL->ClearColor(1.0, 1.0, 1.0, 0.0);
	$OGL->Enable(GL_DEPTH_TEST, GL_CULL_FACE, GL_LIGHT0, GL_LIGHTING);
#$OGL->OnDisplayForMouseZoom()の初期化のために呼んでいるだけ
	$OGL->LookAt(0.0, 0.0, -10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	$OGL->MatrixMode(GL_PROJECTION);
	$OGL->InitializeMatrix();
	$OGL->Perspective(30.0, $WindowWidth / $WindowHeight, 1.0, 100.0);
	$OGL->MatrixMode(GL_MODELVIEW);

#各オブジェクトの色を初期化
	for (my $i = 0; $i < $nObjects ; $i++) {
		$material[$i] = new Graphics::OpenGLMaterial(
				-Diffuse   => $gray,
			);
	}
}
