#=============================================== # Graphics::OpenGL #=============================================== package Graphics::OpenGL; use Common; @ISA = qw(Common); #公開したいサブルーチン #@EXPORT = qw(); use strict; use Sci qw(mod); use OpenGL qw/ :all /; use Utils; use Graphics::OpenGLMaterial; use Sci qw(acos $todeg $torad); #============================================================ # 静的メンバー関数 #============================================================ sub IdentityMatrix { return ( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, -10, 1 ); } #============================================================ # 変数取得関数など #============================================================ #============================================================ # コンストラクタ、デストラクタ #============================================================ sub new { my ($module) = @_; my $this = {}; bless $this; $this->SetOffset(0,0, 0.0, 0.0); return $this; } sub DESTROY { my $this = shift; } #============================================================ # 一般関数 #============================================================ sub Initialize { my ($this, $DisplayMode, $x0, $y0, $w, $h, $WindowTitle, $IsFullScreen) = @_; $DisplayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH if(!defined $DisplayMode); glutInit(); #GLUT_SINGLE | GLUT_RGB #GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitDisplayMode($DisplayMode); if(defined $WindowTitle) { $this->CreateWindow($x0, $y0, $w, $h, 'Test Module', $IsFullScreen); } } sub Clear { my ($this, $mode) = @_; $mode = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT if(!defined $mode); glClear($mode); } sub ClearColor { my ($this, @color) = @_; if(!defined $color[3]) { @color = (0.0, 0.0, 0.0, 1.0); } glClearColor(@color); } sub GenLists { my ($this, $n) = @_; my $objects = glGenLists($n); return $this->{pObjectLists} = $objects; } sub DrawListObject { my ($this, $i) = @_; #ネームスタックの先頭にこれから描くオブジェクトの番号を設定 $this->LoadName($i); #オブジェクトを描画する(画面には表示されない) $this->CallList($i); } sub NewList { my ($this, $i, $mode) = @_; glNewList($this->{pObjectLists} + $i, $mode); } sub EndList { glEndList(); } sub InitNames { glInitNames(); #ネームスタックの先頭に仮の名前を詰めておく #ネームスタック自体は複数のオブジェクトが選択できるように #スタック構造になっているが,今回は1個のオブジェクトしか #選択しないので,ネームスタックの先頭の要素だけを取り替えながら #描画すればよい.そこで,あらかじめネームスタックの先頭に #仮の名前 (-1) に詰めておいて,そこを使い回す glPushName(-1); } sub LoadName { my ($this, $i) = @_; glLoadName($i); } sub ExitSelectionMode { my ($this) = @_; # /* 再び透視変換マトリクスに切替える */ $this->MatrixMode(GL_PROJECTION); # /* 透視変換マトリクスを元に戻す */ $this->PopMatrix(); # /* モデルビューマトリクスに戻す */ $this->MatrixMode(GL_MODELVIEW); # /* レンダリングモードを元に戻す */ my $hits = $this->{nHits} = $this->RenderMode(GL_RENDER); $this->{IsSelectionMode} = 0; return $hits; } sub EnterSelectionMode { my ($this, $x, $y, $dx, $dy) = @_; $this->{IsSelectionMode} = 1; $this->{iObject} = 0; #セレクションに使うバッファの設定 #セレクションモード以外の時(glRenderMode(GL_SELECT) より前)に実行する必要がある. $this->SelectBuffer(); #レンダリングモードをセレクションモードに切替える $this->RenderMode(GL_SELECT); #セレクションバッファの初期化。セレクションモードになってないと無視される $this->InitNames(); #セレクションの処理は視点座標系で行う $this->MatrixMode(GL_PROJECTION); #現在の透視変換マトリクスを保存する $this->PushMatrix(); #透視変換マトリクスを初期化する $this->InitializeMatrix(); #現在のビューポート設定を得る my @viewport = $this->GetIntegerv(GL_VIEWPORT); #表示領域がマウスポインタの周囲だけになるように変換行列を設定する #マウスの座標系は,スクリーンの座標系に対して上下が反転しているので,それを補正する $this->PickMatrix_p($x, $viewport[3] - $y - 1, $dx, $dy, @viewport); #通常の描画と同じ透視変換マトリクスを設定する #ウィンドウ全体をビューポートにしているので,アスペクト比は vp[2] / vp[3] で得られる $this->Perspective(30.0, $viewport[2] / $viewport[3], 1.0, 100.0); # /* モデルビューマトリクスに切替える */ $this->MatrixMode(GL_MODELVIEW); # glNewList(-1, GL_COMPILE); } sub PushMatrix { glPushMatrix(); } sub PopMatrix { glPopMatrix(); } sub ReadPixels { my ($this, $x, $y, $dx, $dy, $mode, $type) = @_; return glReadPixels_p($x, $y, $dx, $dy, $mode, $type); } sub UnProject { #@matrix: @modelview, @projection, @viewport my ($this, $x, $y, $z, @matrix) = @_; return gluUnProject_p($x, $y, $z, @matrix); } sub Get3DPosition { my ($this, $x, $y, $z) = @_; my @viewport = $this->GetViewport(); if(!defined $z) { $z = $this->ReadPixels($x, $viewport[3] - $y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT); } my @model = $this->GetModelviewMatrix(); my @proj = $this->GetProjectionMatrix(); my ($ox, $oy, $oz) = gluUnProject_p($x, $viewport[3] - $y, $z, @model, @proj, @viewport); return ($ox, $oy, $oz); } sub GetDoublev { my ($this, $name) = @_; return glGetDoublev_p($name); } sub GetIntegerv { my ($this, $name) = @_; return glGetIntegerv_p($name); } sub GetModelviewMatrix { my ($this) = @_; return glGetDoublev_p(GL_MODELVIEW_MATRIX); } sub GetProjectionMatrix { my ($this) = @_; return glGetDoublev_p(GL_PROJECTION_MATRIX); } sub GetViewport { my ($this) = @_; return glGetIntegerv_p(GL_VIEWPORT); } sub PickMatrix_p { my ($this, $x, $y, $dx, $dy, @viewport) = @_; if(@viewport < 4) { @viewport = glGetIntegerv_p(GL_VIEWPORT); } gluPickMatrix_p($x, $y, $dx, $dy, @viewport); } sub RenderMode { my ($this, $mode) = @_; glRenderMode($mode); } #セレクションに使うバッファの設定 #セレクションモード以外の時(glRenderMode(GL_SELECT) より前)に実行する必要がある. sub SelectBuffer { my ($this, $n) = @_; $n = $this->{nSelectionBuffer} if(!defined $n); glSelectBuffer_c($n, $this->{pSelectionBuffer}->ptr()); } sub GetSelectionList { my ($this) = @_; my $len = $this->{pSelectionBuffer}->elements(); return $this->{pSelectionBuffer}->retrieve(0, $len-1); } sub GetSelectedObjects { my ($this) = @_; my @pObjects; my @SelArray = $this->GetSelectionList(); my $nHits = $this->{nHits}; my $c = 0; for (my $iObjects = 0; $iObjects < $nHits ; $iObjects++) { my %obj; my $nhit = $obj{nhit} = $SelArray[$c++]; $obj{Zmin} = $SelArray[$c++] / 0x7fffffff; $obj{Zmax} = $SelArray[$c++] / 0x7fffffff; my @iobj; for (my $j = 0 ; $j < $nhit ; $j++) { $iobj[$j] = $SelArray[$c++]; } $obj{piObjects} = \@iobj; $pObjects[$iObjects] = \%obj; } $this->{pSelectedObjectes} = \@pObjects; return @pObjects; } sub CreateSelectionBuffer { my ($this, $n) = @_; my $array = OpenGL::Array->new($n, GL_INT); $this->{nSelectionBuffer} = $n; $this->{pSelectionBuffer} = $array; $this->SelectBuffer(); return $array; } sub CallList { my ($this, $i) = @_; glCallList($this->{pObjectLists} + $i); } sub Flush { glFlush(); } sub Enable { my ($this, @a) = @_; for(my $i = 0 ; $i < @a ; $i++) { glEnable($a[$i]); } } sub ShadeModel { my ($this, $model) = @_; glShadeModel($model); } sub MatrixMode { my ($this, $mode) = @_; glMatrixMode($mode); } sub InitializeMatrix { my ($this) = @_; glLoadIdentity(); } sub Run { my ($OGL) = @_; glutMainLoop(); } sub Show { my ($this) = @_; glutSwapBuffers(); } sub Redraw { my ($OGL) = @_; glutPostRedisplay(); } sub PostRedisplay { my ($OGL) = @_; glutPostRedisplay(); } sub LookAt { my ($this, $EyeX, $EyeY, $EyeZ, $TargetX, $TargetY, $TargetZ, $UpvectorX, $UpvectorY, $UpvectorZ) = @_; $this->{lookat_eyex} = $EyeX; $this->{lookat_eyey} = $EyeY; $this->{lookat_eyez} = $EyeZ; $this->{lookat_targetx} = $TargetX; $this->{lookat_targety} = $TargetY; $this->{lookat_targetz} = $TargetZ; $this->{lookat_upvectorx} = $UpvectorX; $this->{lookat_upvectory} = $UpvectorY; $this->{lookat_upvectorz} = $UpvectorZ; gluLookAt($EyeX, $EyeY, $EyeZ, $TargetX, $TargetY, $TargetZ, $UpvectorX, $UpvectorY, $UpvectorZ); } sub Perspective { my ($this, $ViewAngle, $AspectRatioWdivH, $zNear, $zFar) = @_; $this->{perspective_aspectratio} = $AspectRatioWdivH; $this->{perspective_znear} = $zNear; $this->{perspective_zFar} = $zFar; gluPerspective($ViewAngle, $AspectRatioWdivH, $zNear, $zFar); } sub Viewport { my ($this, @a) = @_; glViewport(@a); } sub Rotated { my ($this, $angle, $vx, $vy, $vz) = @_; glRotated($angle, $vx, $vy, $vz); } sub Translated { my ($this, $x, $y, $z) = @_; glTranslated($x, $y, $z); } sub glLight { my ($this, $object, $action, $p) = @_; glLightfv_p($object, $action, @$p); } sub SetLight { my ($this, $object, $material) = @_; $this->glLight($object, GL_POSITION, $material->{-Position}) if($material->{-Position}); $this->glLight($object, GL_DIFFUSE, $material->{-Diffuse} ) if($material->{-Diffuse}); $this->glLight($object, GL_AMBIENT, $material->{-Ambient} ) if($material->{-Ambient}); $this->glLight($object, GL_SPECULAR, $material->{-Specular}) if($material->{-Specular}); } sub glMaterial { my ($this, $object, $action, $p) = @_; glMaterialfv_p($object, $action, @$p); } sub SetMaterial { my ($this, $material, $side) = @_; return if(!defined $material); $side = GL_FRONT | GL_BACK if(!defined $side); $this->glMaterial($side, GL_DIFFUSE, $material->{-Diffuse} ) if($material->{-Diffuse}); $this->glMaterial($side, GL_AMBIENT, $material->{-Ambient} ) if($material->{-Ambient}); $this->glMaterial($side, GL_SPECULAR, $material->{-Specular}) if($material->{-Specular}); $this->glMaterial($side, GL_EMISSION, $material->{-Emission}) if($material->{-Emission}); $this->glMaterial($side, GL_SHININESS, $material->{-Shininess}) if($material->{-Shininess}); } sub CalTransform { my ($this, $x0, $y0, $z0, $x1, $y1, $z1) = @_; $x0 -= $this->{offset_cx}; $y0 -= $this->{offset_cy}; $z0 -= $this->{offset_cz}; $x1 -= $this->{offset_cx}; $y1 -= $this->{offset_cy}; $z1 -= $this->{offset_cz}; my $centerx = ($x0 + $x1) / 2.0; my $centery = ($y0 + $y1) / 2.0; my $centerz = ($z0 + $z1) / 2.0; my $dx = $x1 - $x0; my $dy = $y1 - $y0; my $dz = $z1 - $z0; my $r = $dx*$dx + $dy*$dy + $dz*$dz; $r = sqrt($r); my $cosQ = $dy / $r; my $Q = acos($cosQ) * $todeg; my ($rotationx, $rotationy, $rotationz) = ($dz, 0, -$dx); if(abs($dx) <= 1.0e-4 and abs($dz) <= 1.0e-4) { ($rotationx, $rotationy, $rotationz) = (1.0, 0, 0.0); } return ($r, $centerx, $centery, $centerz, $rotationx, $rotationy, $rotationz, $Q); } sub DrawCube { my ($this, $x, $y, $z, $size, $material) = @_; $x -= $this->{offset_cx}; $y -= $this->{offset_cy}; $z -= $this->{offset_cz}; $this->SetMaterial($material, GL_FRONT); glPushMatrix(); glTranslated($x, $y, $z); glutSolidCube($size); glPopMatrix(); } sub DrawSphere { my ($this, $x, $y, $z, $radius, $material, $nsides) = @_; $x -= $this->{offset_cx}; $y -= $this->{offset_cy}; $z -= $this->{offset_cz}; $nsides = 12 if(!defined $nsides); $this->SetMaterial($material, GL_FRONT); glPushMatrix(); glTranslated($x, $y, $z); if($this->{IsSelectionMode}) { #print "sel: $this->{iObject}\n"; # glNewList($this->{iObject}++, GL_COMPILE); glPushName($this->{iObject}++); glutSolidSphere($radius, $nsides, $nsides); glPopName(); # glEndList(); } else { glutSolidSphere($radius, $nsides, $nsides); } glPopMatrix(); } sub DrawCylinder { my ($this, $x0, $y0, $z0, $x1, $y1, $z1, $radius, $material, $nsides) = @_; #CalTransform内で原点補正を行うので、ここでは何もしない # $x0 -= $this->{offset_cx}; # $y0 -= $this->{offset_cy}; # $z0 -= $this->{offset_cz}; # $x1 -= $this->{offset_cx}; # $y1 -= $this->{offset_cy}; # $z1 -= $this->{offset_cz}; my ($r, $centerx, $centery, $centerz, $rotationx, $rotationy, $rotationz, $Q) = $this->CalTransform($x0, $y0, $z0, $x1, $y1, $z1); #print "($r, $centerx, $centery, $centerz, $rotationx, $rotationy, $rotationz, $Q)\n"; glPushMatrix(); glTranslated($centerx, $centery, $centerz); glRotatef($Q, $rotationx, $rotationy, $rotationz); # glTranslated($centerx, $centery, $centerz); if($this->{IsSelectionMode}) { glPushName($this->{iObject}++); $this->DrawCylinder0(0.0, 0.0, 0.0, $radius, $r, $material, $nsides); glPopName(); } else { $this->DrawCylinder0(0.0, 0.0, 0.0, $radius, $r, $material, $nsides); } glPopMatrix(); } sub DrawCylinder0 { my ($this, $x, $y, $z, $radius, $height, $material, $nsides) = @_; #print "n: $nsides,$material, $radius\n"; #CalTransform内で原点補正を行うので、ここでは何もしない # $x -= $this->{offset_cx}; # $y -= $this->{offset_cy}; # $z -= $this->{offset_cz}; $nsides = 12 if(!defined $nsides); my $step = 6.28318530717958647692 / $nsides; # $height = $height / 2; my $ytop = $height/2.0; my $ybottom = -$height/2.0; $this->SetMaterial($material, GL_FRONT); 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), $ytop, $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), $ybottom, $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, $ytop, $radius * $zz); glVertex3f($radius * $xx, $ybottom, $radius * $zz); } glEnd(); glPopMatrix(); } sub DrawGround { my ($this, $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 SetOffset { my ($this, $cx, $cy, $cz) = @_; $this->{offset_cx} = $cx; $this->{offset_cy} = $cy; $this->{offset_cz} = $cz; } sub SetFunctions { my ($this, @a) = @_; my %Hash; Utils::ListToHash(\@a, \%Hash); if(defined $Hash{-Reshape}) { if($Hash{-Reshape} eq '') { glutReshapeFunc(); } else { glutReshapeFunc($Hash{-Reshape}); } } if(defined $Hash{-Display}) { if($Hash{-Display} eq '') { glutDisplayFunc(); } else { glutDisplayFunc($Hash{-Display}); } } if(defined $Hash{-Mouse}) { if($Hash{-Mouse} eq '') { glutMouseFunc(); } else { glutMouseFunc($Hash{-Mouse}); } } if(defined $Hash{-Motion}) { if($Hash{-Motion} eq '') { glutMotionFunc(); } else { glutMotionFunc($Hash{-Motion}); } } if(defined $Hash{-Keyboard}) { if($Hash{-Keyboard} eq '') { glutKeyboardFunc(); } else { glutKeyboardFunc($Hash{-Keyboard}); } } if(defined $Hash{-Special}) { if($Hash{-Special} eq '') { glutSpecialFunc(); } else { glutSpecialFunc($Hash{-Special}); } } if(defined $Hash{-Visibility}) { if($Hash{-Visibility} eq '') { glutVisibilityFunc(); } else { glutVisibilityFunc($Hash{-Visibility}); } } if(defined $Hash{-Timer}) { if($Hash{-Timer} eq '') { glutTimerFunc(); } else { glutTimerFunc($Hash{-DelayTime}, $Hash{-Timer}, $Hash{-svalue}); } } if(defined $Hash{-Idle}) { if($Hash{-Idle} eq '') { glutIdleFunc(); } else { glutIdleFunc($Hash{-Idle}); } } } sub CreateWindow { my ($this, $x0, $y0, $w, $h, $WindowTitle, $IsFullScreen) = @_; $IsFullScreen = 0 if(!defined $IsFullScreen); glutInitWindowPosition($x0, $y0); glutInitWindowSize($w, $h); glutCreateWindow($WindowTitle); glutFullScreen() if($IsFullScreen); } sub display { my ($this) = @_; 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); # $this->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 errCallBack { my ($this, $errCode) = @_; my $estring = gluErrorString($errCode); print("Quadric Error: $estring\n"); exit; } sub glDrawCylinder { my ($this, $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 IsFuncPressed { my ($this, $num) = @_; return glutGetModifiers() == eval("GLUT_KEY_F$num"); } sub IsShiftPressed { return glutGetModifiers() == GLUT_ACTIVE_SHIFT; } sub IsCtrlPressed { return glutGetModifiers() == GLUT_ACTIVE_CTRL; } sub GetModifiers { return glutGetModifiers(); } sub keyboard { my ($this, $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) { if($key == unpack('c', 'q') or $key == unpack('c', 'Q')) { exit; } else { } } sub mouse { my ($this, $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 { } } #====================================================================== # マウスに応答して移動、回転 #====================================================================== #my @SaveModelviewMatrix; # = Graphics::OpenGL::IdentityMatrix(); #my @SaveProjectionMatrix; # = Graphics::OpenGL::IdentityMatrix(); #====================================================================== # マウスに応答してズーム(視点位置、視野角) #====================================================================== sub OnInitializeForMouseZoom { my ($this, $EyeZ, $ViewAngle) = @_; $this->{zoom_eyez} = $EyeZ; $this->{zoom_viewangle} = $ViewAngle; $this->{zoom_x0} = 0.0; $this->{zoom_y0} = 0.0; $this->{zoom_sx} = 1.0; $this->{zoom_sy} = 1.0; } sub OnDisplayForMouseZoom { my ($this) = @_; $this->MatrixMode(GL_PROJECTION); $this->InitializeMatrix(); $this->Perspective($this->{zoom_viewangle}, $this->{perspective_aspectratio}, $this->{perspective_znear}, $this->{perspective_zFar}); $this->MatrixMode(GL_MODELVIEW); $this->LookAt($this->{lookat_eyex}, $this->{lookat_eyey}, $this->{zoom_eyez}, $this->{lookat_targetx}, $this->{lookat_targety}, $this->{lookat_targetz}, $this->{lookat_upvectorx}, $this->{lookat_upvectory}, $this->{lookat_upvectorz}); } sub OnResizeForMouseZoom { my ($this, $w, $h) = @_; # $this->{zoom_sx} = $w; # $this->{zoom_sy} = $h; $this->MatrixMode(GL_PROJECTION); $this->InitializeMatrix(); $this->Perspective($this->{zoom_viewangle}, $this->{perspective_aspectratio}, $this->{perspective_znear}, $this->{perspective_zFar}); $this->MatrixMode(GL_MODELVIEW); $this->LookAt($this->{lookat_eyex}, $this->{lookat_eyey}, $this->{zoom_eyez}, $this->{lookat_targetx}, $this->{lookat_targety}, $this->{lookat_targetz}, $this->{lookat_upvectorx}, $this->{lookat_upvectory}, $this->{lookat_upvectorz}); } sub OnDrawForMouseZoom { my ($this) = @_; } sub OnMotionForMouseZoom { my ($this, $x, $y) = @_; #print "eye: $this->{zoom_eyez}, $this->{zoom_viewangle} => "; $this->{zoom_eyez} += $this->{zoom_sx} * ($x - $this->{zoom_x0}); $this->{zoom_viewangle} -= $this->{zoom_sy} * ($y - $this->{zoom_y0}); $this->{zoom_viewangle} = 3.0 if($this->{zoom_viewangle} < 3.0); $this->{zoom_viewangle} = 85.0 if($this->{zoom_viewangle} > 85.0); #print " $this->{zoom_eyez}, $this->{zoom_viewangle}\n"; $this->{zoom_x0} = $x; $this->{zoom_y0} = $y; $this->Redraw(); } sub OnMouseDownForMouseZoom { my ($this, $x, $y) = @_; $this->{zoom_x0} = $x; $this->{zoom_y0} = $y; } sub OnMouseUpForMouseZoom { my ($this, $x, $y) = @_; } #====================================================================== # マウスに応答して移動 #====================================================================== sub OnInitializeForMouseTranslation { my ($this) = @_; $this->{translation_sx} = 1.0; $this->{translation_sy} = 1.0; $this->{translation_x0} = 0.0; $this->{translation_y0} = 0.0; $this->{translation_cx} = 0.0; $this->{translation_cy} = 0.0; $this->{translation_cz} = 0.0; } sub OnDisplayForMouseTranslation { my ($this) = @_; $this->InitializeMatrix(); } sub OnResizeForMouseTranslation { my ($this, $w, $h, $k) = @_; $k = 1.0 if(!defined $k); $this->{translation_sx} = $k / $w; $this->{translation_sy} = $k / $h; } sub OnDrawForMouseTranslation { my ($this) = @_; $this->Translated($this->{translation_cx}, -$this->{translation_cy}, $this->{translation_cz}); } sub OnMotionForMouseTranslation { my ($this, $x, $y) = @_; $this->{translation_cx} += $this->{translation_sx} * ($x - $this->{translation_x0}); $this->{translation_cy} += $this->{translation_sy} * ($y - $this->{translation_y0}); # $this->{translation_cz} $this->Redraw(); $this->{translation_x0} = $x; $this->{translation_y0} = $y; } sub OnMouseDownForMouseTranslation { my ($this, $x, $y) = @_; $this->{translation_x0} = $x; $this->{translation_y0} = $y; } sub OnMouseUpForMouseTranslation { my ($this, $x, $y) = @_; } #====================================================================== # マウスに応答して回転 #====================================================================== sub OnInitializeForMouseRotation { my ($this) = @_; $this->{rotation_cx} = 0.0; $this->{rotation_cy} = 0.0; $this->{rotation_sx} = 1.0; $this->{rotation_sy} = 1.0; $this->{rotation_ax} = 0.0; $this->{rotation_ay} = 1.0; $this->{rotation_az} = 0.0; $this->{rotation_angle} = 0.0; $this->{rotation_ca} = 0.0; } sub OnDisplayForMouseRotation { my ($this) = @_; # if(@SaveProjectionMatrix < 16) { $this->InitializeMatrix(); # @SaveModelviewMatrix = $this->GetModelviewMatrix(); # @SaveProjectionMatrix = $this->GetProjectionMatrix(); # } # else { # $this->InitializeMatrix(); ## $this->MatrixMode(GL_PROJECTION); ## glLoadMatrixd_p(@SaveProjectionMatrix); ## $this->MatrixMode(GL_MODELVIEW); ## glLoadMatrixd_p(@SaveModelviewMatrix); # } } sub OnResizeForMouseRotation { my ($this, $w, $h) = @_; $this->{rotation_sx} = 1.0 / $w; $this->{rotation_sy} = 1.0 / $h; } sub OnDrawForMouseRotation { my ($this) = @_; $this->Rotated($this->{rotation_angle}, $this->{rotation_ax}, $this->{rotation_ay}, $this->{rotation_az}); } sub OnMouseDownForMouseRotation { my ($this, $x, $y) = @_; # $this->{rotation_angle} = 0.0; $this->{rotation_cx} = $x; $this->{rotation_cy} = $y; $this->{rotation_ca} = $this->{rotation_angle}; } sub OnMouseUpForMouseRotation { my ($this, $x, $y) = @_; # @SaveModelviewMatrix = $OGL->GetModelviewMatrix(); # @SaveProjectionMatrix = $OGL->GetProjectionMatrix(); } sub OnMotionForMouseRotation { my ($this, $x, $y) = @_; my $sx = $this->{rotation_sx}; my $sy = $this->{rotation_sy}; my $cx = $this->{rotation_cx}; my $cy = $this->{rotation_cy}; my $ca = $this->{rotation_ca}; #マウスポインタの位置のドラッグ開始位置からの変位 my $dx = ($x - $cx) * $sx; my $dy = ($y - $cy) * $sy; #マウスポインタの位置のドラッグ開始位置からの距離 my $a = sqrt($dx * $dx + $dy * $dy); #print "a=$a, ", $a/$sx, "\n"; if($a/$sx > 5.0) { #距離を角度に換算してドラッグ開始時の回転角に加算 $this->{rotation_angle} = mod($ca + 360.0 * $a, 360.0); #マウスポインタの変位から回転軸ベクトルを求める $this->{rotation_ax} = $dy / $a; $this->{rotation_ay} = $dx / $a; $this->{rotation_az} = 0.0; $this->Redraw(); } } 1;