メモリーリークがあったので少し修正。
とりあえず、ARToolKit 中のサンプルプログラム SimpleTest を Intel Visual Fortran で書き直すことが出来ました。Intel Visual Fortran (Ver.10.1.021) は、Fortran2003 の規格を一部先取りしていて、C 言語との相互連結の部分はすでに使えるようになっているので、今回はコンパイラ独自の拡張形式を使うことなく、Fortran2003 の機能の範囲内で ARToolKit の機能を利用することが出来ました。
(多分 UhoPlot などのこの日記に書いてきた Windows 用コードも、 !DEC で始まるコンパイラ拡張機能を用いることなく Fortran2003 の規格の範囲内で Windows API を利用できると思います。)
実行例
ドラキュラ同様、鏡には映りません。これはマーカーの認識を最大合致の1個のみを選択するようにプログラムされているからです。これを書き換えることで鏡の方にも像を出せるはずです。
以下にソースコードを示します。
構造体の配列のポインターを渡すところで苦労しました。本来は ARToolKit 側で領域を確保するのではと思うのですが、不安定になるので、ここではあらかじめ Fortran 側で ALLOCATE してから渡しました。
Fortran2003 の機能に少し感動しました。完全なインプリメントがなされるとうれしいです。
MODULE m_ART USE, INTRINSIC :: ISO_C_BINDING USE opengl_gl USE opengl_glu USE opengl_glut IMPLICIT NONE !---- TYPE definition --------------------------------- TYPE, BIND(C) :: t_ARParam INTEGER(C_INT) :: ixsize, iysize REAL(C_DOUBLE) :: dmat(4, 3) REAL(C_DOUBLE) :: dist_factor(4) END TYPE ! TYPE, BIND(C) :: t_ARMarkerInfo INTEGER(C_INT) :: iarea INTEGER(C_INT) :: id INTEGER(C_INT) :: dir REAL(C_DOUBLE) :: cf REAL(C_DOUBLE) :: pos(2) REAL(C_DOUBLE) :: dline(3, 4) REAL(C_DOUBLE) :: vertex(2, 4) END TYPE !---- global variable --------------------------------- INTEGER(C_INT) :: ithresh = 100 INTEGER(C_INT) :: icount = 0 INTEGER(C_INT) :: ipatt_id REAL(C_DOUBLE) :: patt_width = 80.0_c_double REAL(C_DOUBLE) :: patt_center(2) = (/0.0_c_double, 0.0_c_double/) REAL(C_DOUBLE) :: patt_trans(3, 4) INTEGER(C_INT) :: ixsize, iysize TYPE(t_ARParam) :: cparam !---- INTERFACE BLOCK ----------------------------------- INTERFACE SUBROUTINE arVideoCapStop() BIND(C, NAME = 'arVideoCapStop') END SUBROUTINE arVideoCapStop ! SUBROUTINE arVideoClose() BIND(C, NAME = 'arVideoClose') END SUBROUTINE arVideoClose ! SUBROUTINE argCleanup() BIND(C, NAME = 'argCleanup') END SUBROUTINE argCleanup ! INTEGER(C_INT) FUNCTION arVideoGetImage() BIND(C, NAME = 'arVideoGetImage') USE, INTRINSIC :: ISO_C_BINDING END ! SUBROUTINE arUtilSleep(i) BIND(C, NAME = 'arUtilSleep') USE, INTRINSIC :: ISO_C_BINDING INTEGER(C_INT), VALUE :: i END ! SUBROUTINE arUtilTimerReset() BIND(C, NAME = 'arUtilTimerReset') USE, INTRINSIC :: ISO_C_BINDING END ! SUBROUTINE argDrawMode2D() BIND(C, NAME = 'argDrawMode2D') END ! SUBROUTINE argDispImage( iptr, i, j ) BIND(C, NAME = 'argDispImage') USE, INTRINSIC :: ISO_C_BINDING INTEGER(C_INTPTR_T), VALUE :: iptr INTEGER, VALUE :: i, j END ! INTEGER(C_INT) FUNCTION arDetectMarker( iptr, i, mark, k ) BIND(C, NAME = 'arDetectMarker') USE, INTRINSIC :: ISO_C_BINDING import INTEGER(C_INTPTR_T), VALUE :: iptr INTEGER(C_INT) , VALUE :: i TYPE(t_ARMarkerInfo), POINTER :: mark(:) INTEGER(C_INT) :: k END ! SUBROUTINE arVideoCapNext() BIND(C, NAME = 'arVideoCapNext') END ! SUBROUTINE argSwapBuffers() BIND(C, NAME = 'argSwapBuffers') END ! SUBROUTINE arGetTransMat(ptr, d1, d, d2) BIND(C, NAME = 'arGetTransMat') USE, INTRINSIC :: ISO_C_BINDING TYPE(C_PTR), VALUE :: ptr REAL(C_DOUBLE), VALUE :: d REAL(C_DOUBLE):: d1(2), d2(3, 4) END ! SUBROUTINE argDrawMode3D() BIND(C, NAME = 'argDrawMode3D') END SUBROUTINE argDrawMode3D ! SUBROUTINE argDraw3dCamera(ix, iy) BIND(C, NAME = 'argDraw3dCamera') USE, INTRINSIC :: ISO_C_BINDING INTEGER(C_INT), VALUE :: ix, iy END ! SUBROUTINE argConvGlpara(x, y) BIND(C, NAME = 'argConvGlpara') USE, INTRINSIC :: ISO_C_BINDING REAL(C_DOUBLE) :: x(4, 3), y(4, 4) END ! SUBROUTINE arVideoCapStart() BIND(C, NAME = 'arVideoCapStart') END ! SUBROUTINE argMainLoop( i, j, k ) BIND(C, NAME = 'argMainLoop') USE, INTRINSIC :: ISO_C_BINDING INTEGER, VALUE :: i TYPE(C_FUNPTR), VALUE :: j, k END ! INTEGER(4) FUNCTION arVideoOpen(text) BIND(C, NAME = 'arVideoOpen') USE, INTRINSIC :: ISO_C_BINDING CHARACTER(c_char) :: text(*) END ! INTEGER(C_INT) FUNCTION arVideoInqSize(ix, iy) BIND(C, NAME = 'arVideoInqSize') USE, INTRINSIC :: ISO_C_BINDING INTEGER(C_INT) :: ix, iy END ! INTEGER(C_INT) FUNCTION arParamLoad(text, i, xparam) BIND(C, NAME = 'arParamLoad') USE, INTRINSIC :: ISO_C_BINDING import :: t_ARParam CHARACTER(c_char) :: text(*) TYPE(t_ARParam) :: xparam INTEGER(C_INT), VALUE :: i END ! SUBROUTINE arParamChangeSize(xparam, i, j, yparam) BIND(C, NAME = 'arParamChangeSize') USE, INTRINSIC :: ISO_C_BINDING import :: t_ARParam TYPE(t_ARParam) :: xparam, yparam INTEGER(C_INT), VALUE :: i, j END ! SUBROUTINE arInitCparam(xparam) BIND(C, NAME = 'arInitCparam' ) import :: t_ARParam TYPE(t_ARParam) :: xparam END ! SUBROUTINE arParamDisp(xparam) BIND(C, NAME = 'arParamDisp') import :: t_ARParam TYPE(t_ARParam) :: xparam END ! INTEGER(4) FUNCTION arLoadPatt(text) BIND(C, NAME = 'arLoadPatt') USE, INTRINSIC :: ISO_C_BINDING CHARACTER(c_char) :: text(*) END ! SUBROUTINE argInit(iptr, d, i1, i2, i3, i4) BIND(C, NAME = 'argInit') USE, INTRINSIC :: ISO_C_BINDING INTEGER(C_INTPTR_T), VALUE :: iptr REAL(C_DOUBLE) , VALUE :: d INTEGER(C_INT) , VALUE :: i1, i2, i3, i4 END ! REAL(8) FUNCTION arUtilTimer() BIND(C, NAME = 'arUtilTimer') END FUNCTION arUtilTimer END INTERFACE CONTAINS !------------------------------------------------- SUBROUTINE init() BIND(C) USE, INTRINSIC :: ISO_C_BINDING USE opengl_gl USE opengl_glu USE opengl_glut IMPLICIT NONE TYPE(t_ARParam) :: wparam CHARACTER (LEN = 35) :: vconf = "Data\\WDM_camera_flipV.xml" // c_null_char CHARACTER (LEN = 35) :: cparam_name = "Data/camera_para.dat" // c_null_char CHARACTER (LEN = 35) :: patt_name = "Data/patt.hiro" // c_null_char ! /* open the video path */ IF( arVideoOpen( vconf ) < 0 ) STOP ! /* find the size of the window */ IF( arVideoInqSize( ixsize, iysize ) < 0 ) STOP PRINT *, "Image size (x,y) = ", ixsize, iysize ! /* set the initial camera parameters */ IF ( arParamLoad( cparam_name, 1, wparam ) < 0 ) THEN PRINT *, "Camera parameter load error !!" STOP END IF CALL arParamChangeSize( wparam, ixsize, iysize, cparam ) CALL arInitCparam( cparam ) PRINT *, "*** Camera Parameter ***" CALL arParamDisp( cparam ) ipatt_id = arLoadPatt( patt_name ) IF ( ipatt_id < 0 ) THEN PRINT *, "pattern load error !!" STOP END IF ! /* open the graphics window */ CALL argInit( LOC(cparam), 1.0_c_double, 0, 0, 0, 0 ) RETURN END SUBROUTINE init !------------------------------------------------- SUBROUTINE mainLoop() BIND(C, NAME = 'mainLoop') IMPLICIT NONE INTEGER(C_INTPTR_T) :: dataPtr TYPE(t_ARMarkerInfo), POINTER:: marker_info(:) INTEGER(C_INT) :: marker_num INTEGER(C_INT) :: j, k LOGICAL, SAVE :: qfirst = .TRUE. IF (qfirst) THEN ALLOCATE(marker_info(50)) ! ? qfirst = .FALSE. END IF dataPtr = arVideoGetImage() IF (dataPtr == 0) THEN CALL arUtilSleep(2) RETURN END IF IF (icount == 0) CALL arUtilTimerReset() icount = icount + 1 CALL argDrawMode2D() CALL argDispImage( dataPtr, 0, 0 ) IF ( arDetectMarker( dataPtr, ithresh, marker_info, marker_num ) < 0 ) THEN CALL cleanup() RETURN END IF CALL arVideoCapNext() k = -1 DO j = 1, marker_num IF (ipatt_id == marker_info(j)%id) THEN IF (k == -1) THEN k = j ELSE IF (marker_info(k)%cf < marker_info(j)%cf ) k = j END IF END IF END DO IF ( k == -1 ) THEN CALL argSwapBuffers() RETURN END IF ! draw-main CALL arGetTransMat( C_LOC(marker_info(k)), patt_center, patt_width, patt_trans ) CALL draw() CALL argSwapBuffers() RETURN END SUBROUTINE mainLoop !------------------------------------------------- SUBROUTINE cleanup() BIND(C) USE, INTRINSIC :: ISO_C_BINDING USE opengl_gl USE opengl_glu USE opengl_glut IMPLICIT NONE CALL arVideoCapStop() CALL arVideoClose() CALL argCleanup() RETURN END SUBROUTINE cleanup !------------------------------------------------- SUBROUTINE keyEvent( key, ix, iy ) BIND(C, NAME = 'keyEvent') USE, INTRINSIC :: ISO_C_BINDING USE opengl_gl USE opengl_glu USE opengl_glut IMPLICIT NONE INTEGER(C_SIGNED_CHAR), VALUE :: key INTEGER(C_INT) , VALUE :: ix, iy IF (key == 27) THEN PRINT *, "*** ", icount / arUtilTimer(), "(frame/sec)" CALL cleanup() STOP END IF RETURN END SUBROUTINE keyEvent !--------------------------------------------------------------- SUBROUTINE draw() BIND(C) USE, INTRINSIC :: ISO_C_BINDING USE opengl_gl USE opengl_glu USE opengl_glut IMPLICIT NONE REAL(gldouble) :: gl_para(4, 4) REAL(glfloat ) :: mat_ambient(4) = (/0.0_glfloat, 0.0_glfloat, 1.0_glfloat, 1.0_glfloat/) REAL(glfloat ) :: mat_flash(4) = (/0.0_glfloat, 0.0_glfloat, 1.0_glfloat, 1.0_glfloat/) REAL(glfloat ) :: mat_flash_shiny(1) = (/50.0/) REAL(glfloat ) :: light_position(4) = (/100.0_glfloat, -200.0_glfloat, 200.0_glfloat, 0.0_glfloat/) REAL(glfloat ) :: ambi(4) = (/0.1_glfloat, 0.1_glfloat, 0.1_glfloat, 0.1_glfloat/) REAL(glfloat ) :: lightZeroColor(4) = (/0.9_glfloat, 0.9_glfloat, 0.9_glfloat, 0.1_glfloat/) ! CALL argDrawMode3D() CALL argDraw3dCamera( 0, 0 ) CALL glClearDepth( 1.0_gldouble ) CALL glClear(GL_DEPTH_BUFFER_BIT) CALL glEnable(GL_DEPTH_TEST) CALL glDepthFunc(GL_LEQUAL) ! /* load the camera transformation matrix */ CALL argConvGlpara(patt_trans, gl_para) CALL glMatrixMode(GL_MODELVIEW) CALL glLoadMatrixd( gl_para ) CALL glEnable(GL_LIGHTING) CALL glEnable(GL_LIGHT0) CALL glLightfv(GL_LIGHT0, GL_POSITION, light_position) CALL glLightfv(GL_LIGHT0, GL_AMBIENT, ambi) CALL glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor) CALL glMaterialfv(GL_FRONT, GL_SPECULAR, mat_flash) CALL glMaterialfv(GL_FRONT, GL_SHININESS, mat_flash_shiny) CALL glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient) CALL glMatrixMode(GL_MODELVIEW) CALL glTranslatef( 0.0_glfloat, 0.0_glfloat, 150.0_glfloat ) CALL glutWireSphere( 30.0_gldouble, 10, 10 ) CALL glTranslatef( 0.0_glfloat, 0.0_glfloat, -75.0_glfloat ) CALL glScalef( 40.0_glfloat, 40.0_glfloat, 40.0_glfloat ) CALL glutSolidOctahedron() CALL glDisable( GL_LIGHTING ) CALL glDisable( GL_DEPTH_TEST ) RETURN END SUBROUTINE draw !------------------------------------------------------------- END MODULE m_ART !============================================================= PROGRAM main1 USE m_art IMPLICIT NONE CALL glutInit() CALL init() CALL arVideoCapStart() CALL argMainLoop( 0, C_FUNLOC(keyEvent), C_FUNLOC(mainLoop) ) STOP END PROGRAM main1