リンクその2:影のある積み木プロジェクト [コード](2012/12/8改訂) ! Neo cubes ver 6.39 ! (C) 1985 - 2012 by (名前を入れてください) ! 横表示用 ! オプション /Qip /O3 /Qparallel /QxHost ! リンカー追加ライブラリー mkl_solver.lib mkl_intel_c_dll.lib mkl_intel_thread_dll.lib mkl_core_dll.lib mkl_lapack95.lib ! 「面のグループ化」アルゴリズム実験(建物に有利)maxcapture 要調整 ! 長い影を切り取り正しく表示する ! 表示面を切り取り正しく表示する include 'lapack.f90' !LAPACKを使用する !共通変数 module common_variables use ifqwin use lapack95 !LAPACKを使用する use f95_precision !LAPACKを使用する !Graphic画面の大きさを定数で定義する(1600 x 900) integer(2), parameter :: size_x=1600, size_y=900 !チャイルドウインドウの装置番号 integer(4), parameter :: defaultwindow=0, childwindow1=2 !テキスト出力ウインドウの装置番号 integer(4), parameter :: textwindow=2 !テキスト出力横座標 integer(4), parameter :: text_x=1 !各種受け渡し変数 integer(4) result integer(2) result2 type (xycoord) xy TYPE (wxycoord) wxy TYPE (rccoord) curpos integer(2) key !仮想画面 (x, y) integer(4) vram(0:size_x-1, 0:size_y-1) integer(4) vram2(0:size_x-1, 0:size_y-1) integer(4) vram3(0:size_x-1, 0:size_y-1) !四角リージョン変数 (0, 0)-(size_x-1, size_y-1) のリージョンが最初に1度だけ設定される real(8) rctx(0:3), rcty(0:3) !頂点の座標(定数) real(8) rctrgn_a(0:3), rctrgn_b(0:3), rctrgn_c(0:3) !各辺のabc real(8) rctrgn_sign(0:3) !ポリゴンリージョンの真ん中の点の各辺に対する符号 !3角形表示作業用変数 integer(2) trix(0:2), triy(0:2) !リージョンに表示しようとするポリゴンの頂点 integer(2) dots !poly()用 real(8) plx(0:31), ply(0:31) type (xycoord) dispdata(0:31) integer(2) rgnxm, rgnym, rgnxp, rgnyp integer(2) rgnxm2, rgnym2, rgnxp2, rgnyp2 integer(2) afterpolydots !交点計算用入力変数 real(8) crx(0:3), cry(0:3) !頂点、交点のバッファ real(8) cxbuf(0:31), cybuf(0:31) integer(2) ptrcbuf(0:31) real(8) degree_cbuf(0:31) integer(2) spcbuf !getabc用変数 real(8) line_x0, line_y0, line_x1, line_y1 real(8) line_a, line_b, line_c !ポリゴン表示用変数(3〜32角形) TYPE (wxycoord) polydata(0:31) !getabcd用変数 real(8) sur_x0, sur_y0, sur_z0, sur_x1, sur_y1, sur_z1, sur_x2, sur_y2, sur_z2 real(8) sur_a, sur_b, sur_c, sur_d !立方体の色 integer(4) cubecolor(0:5) !影の色(and処理) integer(4), parameter :: shadowcolor=16#7f7f7f !回転前の面オフセット(定数) cubeoffset(xyz, 頂点番号, 面番号) real(8) cubeoffset(0:2, 0:3, 0:5) !回転後の面オフセット rotoffset(xyz, 頂点番号, 面番号) real(8) rotoffset(0:2, 0:3, 0:5) !接する面の方向オフセット(定数) dircontoffset(xyz, 面番号) integer(4) dircontoffset(0:2, 0:5) !回転用グローバル変数 real(8) rxx, ryy, rzz !視点の位置 integer(4) eye(0:2) !視点の方向 real(8) matrix0(0:2, 0:2) real(8) matrix(0:2, 0:2) real(8) seev(0:2) !回転用定数 real(8) sin_t, cos_t !光源のベクトル real(8) ray(0:2) real(8) rotray(0:2) !回転後の光源ベクトル !立方体の座標データ integer(4), parameter :: maxcubes=10000 integer(4) cube(0:2, 0:maxcubes-1) !cube(xyz, 通し番号) integer(4) ptrcube !現在の立方体の個数 real(8) rot(0:2, 0:maxcubes-1) !回転後のデータ real(8) rot_a(0:5), rot_b(0:5), rot_c(0:5) !abc(面番号) real(8) rot_d(0:5, 0:maxcubes-1) !d(面番号, 通し番号) logical(4) act(0:5, 0:maxcubes-1) !act(面番号, 通し番号) logical(4) actshadow(0:5) !actshadow(面番号) logical(4) actcontact(0:5, 0:maxcubes-1) !actcontact(面番号, 通し番号)互いに接している面は除外する real(8) sur(0:2, 0:3, 0:5, 0:maxcubes-1) !sur(xyz, 頂点番号, 面番号, 通し番号)頂点の座標 integer(4) sortptr(0:maxcubes-1) integer(4) endofsortptr !現在のソートポインタの個数 real(8) distance(0:maxcubes-1) real(8) signc(0:5) !signc(面番号)立方体の真ん中の点について、6つの面に対する正負を計算 real(8) centerpoint(0:2, 0:5, 0:maxcubes-1) !centerpoint(xyz, 面番号, 通し番号) 各面の真ん中の点 !面のグループ化 integer(4) ppgroup, pgroupforcube real(8) groupd(0:maxcubes*3-1) integer(4) groupforsurface(0:maxcubes*3-1) integer(4) ptrgroup(0:maxcubes*3-1) integer(4) groupforserial(0:maxcubes*3-1) integer(4) endofnext(0:maxcubes*3-1) integer(4) nextptr(0:maxcubes*3-1) integer(4) ppsort integer(4) sortc(0:maxcubes*3-1) logical(4) identity(0:maxcubes-1) logical(4) isrgnsetted integer(4), parameter :: maxcapture=maxcubes*8000 !*******要調整 integer(4) rgnxmgroup, rgnxpgroup, rgnymgroup, rgnypgroup integer(4) capture(0:maxcapture-1) !カットライン付近の処理 integer(4) ptrcut(0:5, 0:maxcubes-1) !ptrcut(面番号, 通し番号) 各立方体の各面について、カットライン付近の切り取り処理後の座標データがある場合はそのポインタを返す。無ければ-1 integer(4) endofcutangles !cutanglesへのポインタ integer(4), parameter :: maxcutangles=20000 !*******要調整 real(8) cutangles(0:maxcutangles-1) !頂点の数、頂点x0,y0, x1,y1, ・・・のデータ real(8), parameter :: sqr3d2=0.867_8 !sqr(3)/2 !影の表示モード logical(4) shadowmode logical(4) detailmode !スクリーンのZ座標 real(8) cutline, screen, eyeoffset real(8) cutline2 !Detail mode用 integer(1) screenmode !表示倍率 integer(4) zoom !回転1ストロークあたりの分割数(大きくすると、なめらかに回転する) integer(4), parameter :: rollingdiv=10 !ファイル操作 !ファイル読み出し、書き込み用装置番号 integer(4), parameter :: fileequipnumber=11 integer(2) filenumber !ファイル番号 character(10) filenamelist(35) !表示面のカウンタ(デバッグ用)******* integer(4) surfacecount, shadowcount logical(4) debugmode integer(2) capturepercent integer(2) cutanglespercent logical(4) helpmode end module common_variables !メインプログラム use common_variables implicit none integer(4) j, k, co integer(1) d1,d2,d3 integer(4) d integer(4) the_offset, the_ptr real(8) clock_start, clock_stop, dclock INTEGER(1), ALLOCATABLE:: gbuf (:) INTEGER(2) error INTEGER(4) imsize imsize = IMAGESIZE (INT2(0), INT2(0), INT2(size_x-1), INT2(size_y-1)) ALLOCATE(gbuf(imsize), STAT = error) IF (error .NE. 0) THEN STOP 'ERROR: Insufficient memory' END IF !デバッグモードを初期化する debugmode=.false. !ヘルプ表示モードを初期化する helpmode=.false. !vram2, vram3 をクリアする vram2=0 vram3=16#ffffff !四角リージョンを初期設定する call setrctrgn() !ファイル名を初期設定する filenamelist(1)='cube1.txt' filenamelist(2)='cube2.txt' filenamelist(3)='cube3.txt' filenamelist(4)='cube4.txt' filenamelist(5)='cube5.txt' filenamelist(6)='cube6.txt' filenamelist(7)='cube7.txt' filenamelist(8)='cube8.txt' filenamelist(9)='cube9.txt' filenamelist(10)='cube10.txt' !a filenamelist(11)='cube11.txt' !b filenamelist(12)='cube12.txt' !c filenamelist(13)='cube13.txt' !d filenamelist(14)='cube14.txt' !e filenamelist(15)='cube15.txt' !f filenamelist(16)='cube16.txt' !g filenamelist(17)='cube17.txt' !h filenamelist(18)='cube18.txt' !i filenamelist(19)='cube19.txt' !j filenamelist(20)='cube20.txt' !k filenamelist(21)='cube21.txt' !l filenamelist(22)='cube22.txt' !m filenamelist(23)='cube23.txt' !n filenamelist(24)='cube24.txt' !o filenamelist(25)='cube25.txt' !p filenamelist(26)='cube26.txt' !q filenamelist(27)='cube27.txt' !r filenamelist(28)='cube28.txt' !s filenamelist(29)='cube29.txt' !t filenamelist(30)='cube30.txt' !u filenamelist(31)='cube31.txt' !v filenamelist(32)='cube32.txt' !w filenamelist(33)='cube33.txt' !x filenamelist(34)='cube34.txt' !y filenamelist(35)='cube35.txt' !z !影表示モードを初期設定する shadowmode=.false. detailmode=.false. !立方体の個数=0と初期設定する ptrcube=0 !スクリーンモード設定 screenmode=1 !1 または 2 call setcutline() !sin_t, cos_t(定数)を設定する sin_t= dsin(datan(1.0_8)/45*90/rollingdiv) cos_t= dcos(datan(1.0_8)/45*90/rollingdiv) !視点を初期設定する !位置 eye(0)=10000 eye(1)=10000 eye(2)=10000 !方向 call reseteye001() !光源ベクトルを初期設定する ray(0)=0.0_8 ray(1)=0.0_8 ray(2)=1.0_8 !オフセット(定数)を設定する !面番号0 = x- cubeoffset(0,0,0)=-0.5_8 !x cubeoffset(1,0,0)=-0.5_8 !y cubeoffset(2,0,0)=-0.5_8 !z cubeoffset(0,1,0)=-0.5_8 !x cubeoffset(1,1,0)=+0.5_8 !y cubeoffset(2,1,0)=-0.5_8 !z cubeoffset(0,2,0)=-0.5_8 !x cubeoffset(1,2,0)=+0.5_8 !y cubeoffset(2,2,0)=+0.5_8 !z cubeoffset(0,3,0)=-0.5_8 !x cubeoffset(1,3,0)=-0.5_8 !y cubeoffset(2,3,0)=+0.5_8 !z dircontoffset(0,0)=-1 dircontoffset(1,0)=0 dircontoffset(2,0)=0 !面番号1 = x+ cubeoffset(0,0,1)=+0.5_8 !x cubeoffset(1,0,1)=-0.5_8 !y cubeoffset(2,0,1)=-0.5_8 !z cubeoffset(0,1,1)=+0.5_8 !x cubeoffset(1,1,1)=+0.5_8 !y cubeoffset(2,1,1)=-0.5_8 !z cubeoffset(0,2,1)=+0.5_8 !x cubeoffset(1,2,1)=+0.5_8 !y cubeoffset(2,2,1)=+0.5_8 !z cubeoffset(0,3,1)=+0.5_8 !x cubeoffset(1,3,1)=-0.5_8 !y cubeoffset(2,3,1)=+0.5_8 !z dircontoffset(0,1)=+1 dircontoffset(1,1)=0 dircontoffset(2,1)=0 !面番号2 = y- cubeoffset(0,0,2)=-0.5_8 !x cubeoffset(1,0,2)=-0.5_8 !y cubeoffset(2,0,2)=-0.5_8 !z cubeoffset(0,1,2)=+0.5_8 !x cubeoffset(1,1,2)=-0.5_8 !y cubeoffset(2,1,2)=-0.5_8 !z cubeoffset(0,2,2)=+0.5_8 !x cubeoffset(1,2,2)=-0.5_8 !y cubeoffset(2,2,2)=+0.5_8 !z cubeoffset(0,3,2)=-0.5_8 !x cubeoffset(1,3,2)=-0.5_8 !y cubeoffset(2,3,2)=+0.5_8 !z dircontoffset(0,2)=0 dircontoffset(1,2)=-1 dircontoffset(2,2)=0 !面番号3 = y+ cubeoffset(0,0,3)=-0.5_8 !x cubeoffset(1,0,3)=+0.5_8 !y cubeoffset(2,0,3)=-0.5_8 !z cubeoffset(0,1,3)=+0.5_8 !x cubeoffset(1,1,3)=+0.5_8 !y cubeoffset(2,1,3)=-0.5_8 !z cubeoffset(0,2,3)=+0.5_8 !x cubeoffset(1,2,3)=+0.5_8 !y cubeoffset(2,2,3)=+0.5_8 !z cubeoffset(0,3,3)=-0.5_8 !x cubeoffset(1,3,3)=+0.5_8 !y cubeoffset(2,3,3)=+0.5_8 !z dircontoffset(0,3)=0 dircontoffset(1,3)=+1 dircontoffset(2,3)=0 !面番号4 = z- cubeoffset(0,0,4)=-0.5_8 !x cubeoffset(1,0,4)=-0.5_8 !y cubeoffset(2,0,4)=-0.5_8 !z cubeoffset(0,1,4)=+0.5_8 !x cubeoffset(1,1,4)=-0.5_8 !y cubeoffset(2,1,4)=-0.5_8 !z cubeoffset(0,2,4)=+0.5_8 !x cubeoffset(1,2,4)=+0.5_8 !y cubeoffset(2,2,4)=-0.5_8 !z cubeoffset(0,3,4)=-0.5_8 !x cubeoffset(1,3,4)=+0.5_8 !y cubeoffset(2,3,4)=-0.5_8 !z dircontoffset(0,4)=0 dircontoffset(1,4)=0 dircontoffset(2,4)=-1 !面番号5 = z+ cubeoffset(0,0,5)=-0.5_8 !x cubeoffset(1,0,5)=-0.5_8 !y cubeoffset(2,0,5)=+0.5_8 !z cubeoffset(0,1,5)=+0.5_8 !x cubeoffset(1,1,5)=-0.5_8 !y cubeoffset(2,1,5)=+0.5_8 !z cubeoffset(0,2,5)=+0.5_8 !x cubeoffset(1,2,5)=+0.5_8 !y cubeoffset(2,2,5)=+0.5_8 !z cubeoffset(0,3,5)=-0.5_8 !x cubeoffset(1,3,5)=+0.5_8 !y cubeoffset(2,3,5)=+0.5_8 !z dircontoffset(0,5)=0 dircontoffset(1,5)=0 dircontoffset(2,5)=+1 !色を設定する co=255-32*0 !x- cubecolor(0)=co+256*co+65536*co co=255-32*0 !x+ cubecolor(1)=co+256*co+65536*co co=255-32*1 !y- cubecolor(2)=co+256*co+65536*co co=255-32*1 !y+ cubecolor(3)=co+256*co+65536*co co=255-32*2 !z- cubecolor(4)=co+256*co+65536*co co=255-32*2 !z+ cubecolor(5)=co+256*co+65536*co OPEN(childwindow1, file='user', title='Graphics child window-1') !チャイルドウインドウの大きさを設定する call setchildwindowwidth() result = SETACTIVEQQ (defaultwindow) !画面をクリアする result=setcolorrgb(16#000000) result2=RECTANGLE( $GFILLINTERIOR, int2(0), int2(0), int2(size_x-1), int2(size_y-1) ) !クリア画面をそのまま取り込む(最初の謎の54バイトを取得) CALL GETIMAGE (INT2(0), INT2(0), INT2(size_x-1), INT2(size_y-1), gbuf) 111 continue key=16#0000 do while ( (key .ne. ichar('q')) .and. (key .ne. ichar('Q')) ) if(debugmode) clock_start=dclock() !vramをクリアする vram=0 !表示する if(shadowmode .and. detailmode) then call displaydetail() else call displaycube() end if !データを変換する the_offset=54 the_ptr=the_offset do j=0, size_y-1 do k=0, size_x-1 d=vram(k,j) d1= (d/65536 .and. 255) d2= (d/256 .and. 255) d3= (d .and. 255) gbuf(the_ptr+0)=0 gbuf(the_ptr+1)=d1 gbuf(the_ptr+2)=d2 gbuf(the_ptr+3)=d3 the_ptr= the_ptr+4 end do end do !転送する result = SETACTIVEQQ (childwindow1) call putimage( int2(0), int2(0), gbuf, $GPSET ) if(debugmode) clock_stop=dclock() !フォーカス(見せるウインドウ)をチャイルドウインドウ1に設定 result=focusqq(childwindow1) result = SETACTIVEQQ (childwindow1) if(helpmode) then !ヘルプを表示 !文字の出力位置を設定する(Y座標、X座標の順) CALL SETTEXTPOSITION (INT2(1), INT2(text_x), curpos) write(childwindow1,*) '<-------' CALL SETTEXTPOSITION (INT2(2), INT2(text_x), curpos) write(childwindow1,*) ' Neo cubes shader' CALL SETTEXTPOSITION (INT2(3), INT2(text_x), curpos) write(childwindow1,*) ' ------->' CALL SETTEXTPOSITION (INT2(5), INT2(text_x), curpos) write(childwindow1,*) 'key function:' CALL SETTEXTPOSITION (INT2(6), INT2(text_x), curpos) write(childwindow1,*) ' 2,4,6,8,x,y=rotate' CALL SETTEXTPOSITION (INT2(7), INT2(text_x), curpos) write(childwindow1,*) ' z,a,s,w,spc,b=move' CALL SETTEXTPOSITION (INT2(8), INT2(text_x), curpos) write(childwindow1,*) ' 1=create/delete' CALL SETTEXTPOSITION (INT2(9), INT2(text_x), curpos) write(childwindow1,*) ' m=shadow mode' CALL SETTEXTPOSITION (INT2(10), INT2(text_x), curpos) write(childwindow1,*) ' r=ray setting' CALL SETTEXTPOSITION (INT2(11), INT2(text_x), curpos) write(childwindow1,*) ' i=load file' CALL SETTEXTPOSITION (INT2(12), INT2(text_x), curpos) write(childwindow1,*) ' o=save file' CALL SETTEXTPOSITION (INT2(13), INT2(text_x), curpos) write(childwindow1,*) ' e=reset eye' CALL SETTEXTPOSITION (INT2(14), INT2(text_x), curpos) write(childwindow1,*) ' c=screen mode' CALL SETTEXTPOSITION (INT2(15), INT2(text_x), curpos) write(childwindow1,*) ' /=detail mode' !文字ワードラップをoffにする result2 = WRAPON($GWRAPOFF) CALL SETTEXTPOSITION (INT2(16), INT2(text_x), curpos) write(childwindow1,*) 'cubes:', ptrcube CALL SETTEXTPOSITION (INT2(17), INT2(text_x), curpos) write(childwindow1,*) 'pos x:', eye(0) CALL SETTEXTPOSITION (INT2(18), INT2(text_x), curpos) write(childwindow1,*) 'pos y:', eye(1) CALL SETTEXTPOSITION (INT2(19), INT2(text_x), curpos) write(childwindow1,*) 'pos z:', eye(2) CALL SETTEXTPOSITION (INT2(20), INT2(text_x), curpos) write(childwindow1,*) 'surfaces:', surfacecount CALL SETTEXTPOSITION (INT2(21), INT2(text_x), curpos) write(childwindow1,*) 'eye direction:' CALL SETTEXTPOSITION (INT2(22), INT2(text_x), curpos) write(childwindow1,*) real(matrix0(2,0)) CALL SETTEXTPOSITION (INT2(23), INT2(text_x), curpos) write(childwindow1,*) real(matrix0(2,1)) CALL SETTEXTPOSITION (INT2(24), INT2(text_x), curpos) write(childwindow1,*) real(matrix0(2,2)) if(shadowmode) then CALL SETTEXTPOSITION (INT2(25), INT2(text_x), curpos) write(childwindow1,*) 'ray direction:' CALL SETTEXTPOSITION (INT2(26), INT2(text_x), curpos) write(childwindow1,*) real(ray(0)) CALL SETTEXTPOSITION (INT2(27), INT2(text_x), curpos) write(childwindow1,*) real(ray(1)) CALL SETTEXTPOSITION (INT2(28), INT2(text_x), curpos) write(childwindow1,*) real(ray(2)) CALL SETTEXTPOSITION (INT2(29), INT2(text_x), curpos) write(childwindow1,*) 'shadows:', shadowcount if(detailmode) then CALL SETTEXTPOSITION (INT2(30), INT2(text_x), curpos) write(childwindow1,*) 'Detail mode' end if end if if(debugmode) then CALL SETTEXTPOSITION (INT2(31), INT2(text_x), curpos) write(childwindow1,*) 'time=', real(clock_stop-clock_start) end if if( debugmode .and. shadowmode .and. (.not.detailmode) ) then CALL SETTEXTPOSITION (INT2(32), INT2(text_x), curpos) write(childwindow1,*) 'capture=', capturepercent, '%' CALL SETTEXTPOSITION (INT2(33), INT2(text_x), curpos) write(childwindow1,*) 'cutline=', cutanglespercent, '%' end if CALL SETTEXTPOSITION (INT2(34), INT2(text_x), curpos) write(childwindow1,*) 'screen mode=', screenmode else !文字の出力位置を設定する(Y座標、X座標の順) CALL SETTEXTPOSITION (INT2(1), INT2(text_x), curpos) write(childwindow1,*) 'h=help' end if !フォーカス(見せるウインドウ)をチャイルドウインドウ1に設定 result=focusqq(childwindow1) key=incharqq() select case (key) case(ichar('4')) call rolling(2, 0, +1) case(ichar('6')) call rolling(2, 0, -1) case(ichar('8')) call rolling(1, 2, +1) case(ichar('2')) call rolling(1, 2, -1) case(ichar('x')) call rolling(0, 1, -1) case(ichar('y')) call rolling(0, 1, +1) case(ichar('w')) call forwarding(1, +1) case(ichar('z')) call forwarding(1, -1) case(ichar('s')) call forwarding(0, +1) case(ichar('a')) call forwarding(0, -1) case(ichar(' ')) call forwarding(2, +1) case(ichar('b')) call forwarding(2, -1) case(ichar('1')) call insordelcube() case(ichar('m')) shadowmode= .not. shadowmode case(ichar('/')) detailmode= .not. detailmode case(ichar('r')) result=messageboxqq('現在の方向を光源に設定しますか?'C, 'Neo cubes'C, MB$OKCANCEL) if (result .eq. MB$IDOK) then ray(0:2)=matrix0(2,0:2) shadowmode=.true. end if case(ichar('e')) result=messageboxqq('視線をリセットしますか?'C, 'Neo cubes'C, MB$OKCANCEL) if (result .eq. MB$IDOK) call reseteye() case(ichar('i')) call loadfile() case(ichar('o')) call savefile() case(ichar('d')) debugmode=.not.debugmode case(ichar('h')) helpmode=.not.helpmode case(ichar('c')) screenmode=screenmode+1 if(screenmode .eq. 4) then screenmode=1 end if call setcutline() end select end do result=messageboxqq('Qキーが押されました。終了します'C, 'Neo cubes'C, MB$OKCANCEL) if (result .eq. MB$IDCANCEL) goto 111 end !メインウインドウの大きさを設定する logical(4) function initialsettings() use common_variables implicit none integer(4) i type (qwinfo) qwi qwi.type=QWIN$MAX !最大化する i=SetWSizeQQ(QWIN$FRAMEWINDOW, qwi) initialsettings=.true. end function initialsettings !ウインドウの大きさを設定する subroutine setchildwindowwidth() use common_variables implicit none integer(4) i type (qwinfo) qwi qwi.type=QWIN$MIN !最初から表示されているウインドウを最小化する i=SetWSizeQQ(defaultwindow, qwi) qwi.type=QWIN$MAX !1を最大化する i=SetWSizeQQ(childwindow1, qwi) end subroutine setchildwindowwidth real(8) function sgn(a) use common_variables implicit none real(8) a if( a .gt. 0.0_8 ) sgn=1.0_8 if( a .eq. 0.0_8 ) sgn=0.0_8 if( a .lt. 0.0_8 ) sgn=-1.0_8 end function sgn subroutine setcutline() use common_variables implicit none select case (screenmode) case(1) cutline=-0.49_8 cutline2=-0.49_8 !Detail mode用 screen=1.0_8 eyeoffset=1.6_8 zoom=700 case(2) cutline=-1.9_8 cutline2=-1.9_8 !Detail mode用 screen=1.0_8 eyeoffset=2.0_8 !5.0 または 2.0 zoom=300 case(3) cutline=0.0_8 cutline2=0.0_8 !Detail mode用 screen=1.0_8 eyeoffset=5.0_8 !5.0 または 2.0 zoom=400 end select end subroutine setcutline !matrix0(0:2,0:2)を吸着する subroutine reseteye() use common_variables implicit none real(8) s, a, s1, a1 integer(2) j, k, k1 real(8), external :: sgn matrix=0 do j=0, 2 k1=0 s1=matrix0(0,j) a1=dabs(s1) s1=sgn(s1) do k=1, 2 s=matrix0(k,j) a=dabs(s) s=sgn(s) if( a .gt. a1) then k1=k a1=a s1=s end if end do matrix(k1,j)=s1 end do if( (dabs(matrix(0,0))+dabs(matrix(0,1))+dabs(matrix(0,2)) .eq. 1.0_8) .and. (dabs(matrix(1,0))+dabs(matrix(1,1))+dabs(matrix(1,2)) .eq. 1.0_8) .and. (dabs(matrix(2,0))+dabs(matrix(2,1))+dabs(matrix(2,2)) .eq. 1.0_8) ) then matrix0=matrix else result=messageboxqq('吸着できません。方向(0,0,1)に初期化しますか?'C, 'Neo cubes'C, MB$OKCANCEL) if (result .eq. MB$IDOK) call reseteye001() end if end subroutine reseteye subroutine reseteye001() use common_variables implicit none matrix0(0,0)=1.0_8 matrix0(0,1)=0.0_8 matrix0(0,2)=0.0_8 matrix0(1,0)=0.0_8 matrix0(1,1)=1.0_8 matrix0(1,2)=0.0_8 matrix0(2,0)=0.0_8 matrix0(2,1)=0.0_8 matrix0(2,2)=1.0_8 end subroutine reseteye001 !視点(eye(0), eye(1), eye(2))を前方に動かす subroutine forwarding(i, s) use common_variables implicit none integer(4) i, s real(8) x1(0:2) x1(0:2)=0.0_8+eye(0:2) do while( (int4(0.5_8+x1(0)) .eq. eye(0)) .and. (int4(0.5_8+x1(1)) .eq. eye(1)) .and. (int4(0.5_8+x1(2)) .eq. eye(2))) x1(0:2)=x1(0:2)+s*matrix0(i,0:2) end do eye(0:2)=int4(0.5_8+x1(0:2)) end subroutine forwarding !視点(eye(0),eye(1),eye(2))の前方の立方体を追加/削除する subroutine insordelcube() use common_variables implicit none real(8) x1(0:2) integer(4) x2(0:2) integer(4) j,k x1(0:2)=0.0_8+eye(0:2) do while( (int4(0.5_8+x1(0)) .eq. eye(0)) .and. (int4(0.5_8+x1(1)) .eq. eye(1)) .and. (int4(0.5_8+x1(2)) .eq. eye(2))) x1(0:2)=x1(0:2)+matrix0(2,0:2) end do x2(0:2)=int4(0.5_8+x1(0:2)) if( ptrcube .gt. 0 ) then do j=0, ptrcube-1 if( (x2(0).eq.cube(0,j)) .and. (x2(1).eq.cube(1,j)) .and. (x2(2).eq.cube(2,j)) ) goto 100 end do end if if(ptrcube .eq. maxcubes-1) then result=messageboxqq('これ以上作成できません'C, 'Neo cubes'C, MB$OK) goto 200 end if cube(0:2,ptrcube)=x2(0:2) ptrcube=ptrcube+1 goto 200 100 continue if(j .lt. ptrcube-1) then do k=j, ptrcube-2 cube(0:2,k)=cube(0:2,k+1) end do end if ptrcube=ptrcube-1 200 continue end subroutine insordelcube !視点の方向 matrix0 を回転する subroutine rolling(rix, riy, s) use common_variables implicit none integer(2) rix, riy, s integer(2) j, k real(8) r do j=0, 2 r = cos_t * matrix0(rix, j) - s * sin_t * matrix0(riy, j) matrix0(riy, j) = s * sin_t * matrix0(rix, j) + cos_t * matrix0(riy, j) matrix0(rix, j) = r end do !以下は吸着の処理 do j=0, 2 do k=0, 2 if( (dabs(1-dabs(matrix0(k,j))).gt.0.00001) .and. (dabs(matrix0(k,j)).gt.0.00001) ) goto 999 end do end do do j=0, 2 do k=0, 2 if( dabs(1-dabs(matrix0(k,j))).le.0.00001 ) then if(matrix0(k,j).gt.0) then r=1.0_8 else r=-1.0_8 end if else r=0.0_8 end if matrix0(k,j)=r end do end do 999 continue end subroutine rolling subroutine vram_and_or() use common_variables implicit none vram(rgnxm:rgnxp,rgnym:rgnyp)=( vram(rgnxm:rgnxp,rgnym:rgnyp) .and. vram3(rgnxm:rgnxp,rgnym:rgnyp) ) vram(rgnxm:rgnxp,rgnym:rgnyp)=( vram(rgnxm:rgnxp,rgnym:rgnyp) .or. vram2(rgnxm:rgnxp,rgnym:rgnyp) ) end subroutine vram_and_or subroutine drawpolygon21(d) use common_variables implicit none integer(2) d integer(2) x0, y0, x1, y1 integer(2) j4, j5 integer(2) pxx, pyy plx(0:d-1)=polydata(0:d-1).wx ply(0:d-1)=polydata(0:d-1).wy spcbuf=0 dots=d call poly21() afterpolydots=spcbuf if(spcbuf .lt. 3) return !3角形以下では何もしない !点を整数化し、重複する点を除外する !すべての点を含む矩形の範囲を知る j4=0 x0=size_x/2 + int2(cxbuf(ptrcbuf(spcbuf-1))) rgnxm2=x0 rgnxp2=x0 y0=size_y/2 + int2(cybuf(ptrcbuf(spcbuf-1))) rgnym2=y0 rgnyp2=y0 do j5=0, spcbuf-1 x1=size_x/2 + int2(cxbuf(ptrcbuf(j5))) if( x1 .lt. rgnxm2 ) rgnxm2=x1 if( x1 .gt. rgnxp2 ) rgnxp2=x1 y1=size_y/2 + int2(cybuf(ptrcbuf(j5))) if( y1 .lt. rgnym2 ) rgnym2=y1 if( y1 .gt. rgnyp2 ) rgnyp2=y1 if( (x1 .ne. x0) .or. (y1 .ne. y0) ) then dispdata(j4).xcoord=x1 dispdata(j4).ycoord=y1 j4=j4+1 x0=x1 y0=y1 end if end do afterpolydots=j4 if(j4 .lt. 3) return !3角形以下の場合は何もしない !リージョンが明らかに重ならないときは、何もしない if( rgnxp .lt. rgnxm2 ) goto 999 if( rgnyp .lt. rgnym2 ) goto 999 if( rgnxp2 .lt. rgnxm ) goto 999 if( rgnyp2 .lt. rgnym ) goto 999 pxx=dispdata(0).xcoord pyy=dispdata(0).ycoord do j5=1, afterpolydots-2 trix(0)=pxx triy(0)=pyy trix(1)=dispdata(j5).xcoord triy(1)=dispdata(j5).ycoord trix(2)=dispdata(j5+1).xcoord triy(2)=dispdata(j5+1).ycoord call drawtriangle21() end do return 999 continue afterpolydots=0 end subroutine drawpolygon21 subroutine drawtriangle21() use common_variables implicit none integer(4) co integer(2) tmp real(8) dxybig, dxysmall real(8) xbig, xsmall integer(2) left, right integer(2) j integer(2) dybig, dysmall real(8) d !y座標が小さい順に並べる if(triy(0) .gt. triy(1)) then tmp=triy(0) triy(0)=triy(1) triy(1)=tmp tmp=trix(0) trix(0)=trix(1) trix(1)=tmp end if if(triy(0) .gt. triy(2)) then tmp=triy(0) triy(0)=triy(2) triy(2)=tmp tmp=trix(0) trix(0)=trix(2) trix(2)=tmp end if if(triy(1) .gt. triy(2)) then tmp=triy(2) triy(2)=triy(1) triy(1)=tmp tmp=trix(2) trix(2)=trix(1) trix(1)=tmp end if dybig=triy(2)-triy(0) dxybig=(trix(2)-trix(0))/(dybig*2.0_8) !上半分 dysmall=triy(1)-triy(0) dxysmall=(trix(1)-trix(0))/(dysmall*2.0_8) select case (dysmall) case(0) !横一線 left=imin0( trix(0), trix(1) ) right=imax0( trix(0), trix(1) ) vram2(left:right, triy(0))= ( vram2(left:right, triy(0)) .and. shadowcolor ) !塗る case default !一般 xbig=trix(0)+dxybig xsmall=trix(0)+dxysmall !最初の横一線 left=int2( 0.5_8+ dmin1( trix(0)+0.0_8, xbig, xsmall ) ) right=int2( 0.5_8+ dmax1( trix(0)+0.0_8, xbig, xsmall ) ) vram2(left:right, triy(0))= ( vram2(left:right, triy(0)) .and. shadowcolor ) !塗る !中の線 if(dysmall .ge. 2) then do j=triy(0)+1, triy(1)-1 left=int2( 0.5_8+ dmin1( xbig, xsmall, xbig+dxybig*2, xsmall+dxysmall*2 ) ) right=int2( 0.5_8+ dmax1( xbig, xsmall, xbig+dxybig*2, xsmall+dxysmall*2 ) ) vram2(left:right, j)= ( vram2(left:right, j) .and. shadowcolor ) !塗る xbig=xbig+dxybig*2 xsmall=xsmall+dxysmall*2 end do end if !最後の横一線 if(dybig .eq. dysmall) then d=dxybig else d=dxybig*2 end if left=int2( 0.5_8+ dmin1( xbig, xsmall, xbig+d, xsmall+dxysmall ) ) right=int2( 0.5_8+ dmax1( xbig, xsmall, xbig+d, xsmall+dxysmall ) ) vram2(left:right, triy(1))= ( vram2(left:right, triy(1)) .and. shadowcolor ) !塗る end select !下半分 dysmall=triy(2)-triy(1) dxysmall=(trix(2)-trix(1))/(dysmall*2.0_8) select case (dysmall) case(0) !横一線 left=imin0( trix(1), trix(2) ) right=imax0( trix(1), trix(2) ) vram2(left:right, triy(1))= ( vram2(left:right, triy(1)) .and. shadowcolor ) !塗る case default !一般 xbig=trix(2)-dxybig xsmall=trix(2)-dxysmall !最初の横一線 left=int2( 0.5_8+ dmin1( trix(2)+0.0_8, xbig, xsmall ) ) right=int2( 0.5_8+ dmax1( trix(2)+0.0_8, xbig, xsmall ) ) vram2(left:right, triy(2))= ( vram2(left:right, triy(2)) .and. shadowcolor ) !塗る !中の線 if(dysmall .ge. 2) then do j=triy(2)-1, triy(1)+1, -1 left=int2( 0.5_8+ dmin1( xbig, xsmall, xbig-dxybig*2, xsmall-dxysmall*2 ) ) right=int2( 0.5_8+ dmax1( xbig, xsmall, xbig-dxybig*2, xsmall-dxysmall*2 ) ) vram2(left:right, j)= ( vram2(left:right, j) .and. shadowcolor ) !塗る xbig=xbig-dxybig*2 xsmall=xsmall-dxysmall*2 end do end if !最後の横一線 if(dybig .eq. dysmall) then d=dxybig else d=dxybig*2 end if left=int2( 0.5_8+ dmin1( xbig, xsmall, xbig-d, xsmall-dxysmall ) ) right=int2( 0.5_8+ dmax1( xbig, xsmall, xbig-d, xsmall-dxysmall ) ) vram2(left:right, triy(1))= ( vram2(left:right, triy(1)) .and. shadowcolor ) !塗る end select end subroutine drawtriangle21 !(polydata(0).wx,polydata(0).wy) - (polydata(1).wx,polydata(1).wy) - ... - ! (polydata(d-1).wx,polydata(d-1).wy) を色 co で vram にポリゴンを表示する !afterpolydots=実際に描画された多角形の頂点数 subroutine drawpolygon11(co, d) use common_variables implicit none integer(4) co integer(2) d integer(2) x0, y0, x1, y1 integer(2) j4, j5 integer(2) pxx, pyy plx(0:d-1)=polydata(0:d-1).wx ply(0:d-1)=polydata(0:d-1).wy spcbuf=0 dots=d call poly11() afterpolydots=spcbuf if(spcbuf .lt. 3) goto 999 !3角形以下では何もしない !点を整数化し、重複する点を除外する !すべての点を含む矩形の範囲を知る j4=0 x0=size_x/2 + int2(cxbuf(ptrcbuf(spcbuf-1))) rgnxm=x0 rgnxp=x0 y0=size_y/2 + int2(cybuf(ptrcbuf(spcbuf-1))) rgnym=y0 rgnyp=y0 do j5=0, spcbuf-1 x1=size_x/2 + int2(cxbuf(ptrcbuf(j5))) if( x1 .lt. rgnxm ) rgnxm=x1 if( x1 .gt. rgnxp ) rgnxp=x1 y1=size_y/2 + int2(cybuf(ptrcbuf(j5))) if( y1 .lt. rgnym ) rgnym=y1 if( y1 .gt. rgnyp ) rgnyp=y1 if( (x1 .ne. x0) .or. (y1 .ne. y0) ) then dispdata(j4).xcoord=x1 dispdata(j4).ycoord=y1 j4=j4+1 x0=x1 y0=y1 end if end do afterpolydots=j4 if(j4 .lt. 3) goto 999 !3角形以下の場合は何もしない vram2(rgnxm:rgnxp, rgnym:rgnyp)=0 vram3(rgnxm:rgnxp, rgnym:rgnyp)=16#ffffff pxx=dispdata(0).xcoord pyy=dispdata(0).ycoord do j5=1, afterpolydots-2 trix(0)=pxx triy(0)=pyy trix(1)=dispdata(j5).xcoord triy(1)=dispdata(j5).ycoord trix(2)=dispdata(j5+1).xcoord triy(2)=dispdata(j5+1).ycoord call drawtriangle11(co) end do 999 continue end subroutine drawpolygon11 !整数座標( trix(0), triy(0) ) - ( trix(1), triy(1) ) - ( trix(2), triy(2) ) !の3角形を色 co で vram に表示する subroutine drawtriangle11(co) use common_variables implicit none integer(4) co integer(2) tmp real(8) dxybig, dxysmall real(8) xbig, xsmall integer(2) left, right integer(2) j integer(2) dybig, dysmall real(8) d !y座標が小さい順に並べる if(triy(0) .gt. triy(1)) then tmp=triy(0) triy(0)=triy(1) triy(1)=tmp tmp=trix(0) trix(0)=trix(1) trix(1)=tmp end if if(triy(0) .gt. triy(2)) then tmp=triy(0) triy(0)=triy(2) triy(2)=tmp tmp=trix(0) trix(0)=trix(2) trix(2)=tmp end if if(triy(1) .gt. triy(2)) then tmp=triy(2) triy(2)=triy(1) triy(1)=tmp tmp=trix(2) trix(2)=trix(1) trix(1)=tmp end if dybig=triy(2)-triy(0) dxybig=(trix(2)-trix(0))/(dybig*2.0_8) !上半分 dysmall=triy(1)-triy(0) dxysmall=(trix(1)-trix(0))/(dysmall*2.0_8) select case (dysmall) case(0) !横一線 left=imin0( trix(0), trix(1) ) right=imax0( trix(0), trix(1) ) vram2(left:right, triy(0))= co !塗る vram3(left:right, triy(0))= 0 !塗る case default !一般 xbig=trix(0)+dxybig xsmall=trix(0)+dxysmall !最初の横一線 left=int2( 0.5_8+ dmin1( trix(0)+0.0_8, xbig, xsmall ) ) right=int2( 0.5_8+ dmax1( trix(0)+0.0_8, xbig, xsmall ) ) vram2(left:right, triy(0))= co !塗る vram3(left:right, triy(0))= 0 !塗る !中の線 if(dysmall .ge. 2) then do j=triy(0)+1, triy(1)-1 left=int2( 0.5_8+ dmin1( xbig, xsmall, xbig+dxybig*2, xsmall+dxysmall*2 ) ) right=int2( 0.5_8+ dmax1( xbig, xsmall, xbig+dxybig*2, xsmall+dxysmall*2 ) ) vram2(left:right, j)= co !塗る vram3(left:right, j)= 0 !塗る xbig=xbig+dxybig*2 xsmall=xsmall+dxysmall*2 end do end if !最後の横一線 if(dybig .eq. dysmall) then d=dxybig else d=dxybig*2 end if left=int2( 0.5_8+ dmin1( xbig, xsmall, xbig+d, xsmall+dxysmall ) ) right=int2( 0.5_8+ dmax1( xbig, xsmall, xbig+d, xsmall+dxysmall ) ) vram2(left:right, triy(1))= co !塗る vram3(left:right, triy(1))= 0 !塗る end select !下半分 dysmall=triy(2)-triy(1) dxysmall=(trix(2)-trix(1))/(dysmall*2.0_8) select case (dysmall) case(0) !横一線 left=imin0( trix(1), trix(2) ) right=imax0( trix(1), trix(2) ) vram2(left:right, triy(1))= co !塗る vram3(left:right, triy(1))= 0 !塗る case default !一般 xbig=trix(2)-dxybig xsmall=trix(2)-dxysmall !最初の横一線 left=int2( 0.5_8+ dmin1( trix(2)+0.0_8, xbig, xsmall ) ) right=int2( 0.5_8+ dmax1( trix(2)+0.0_8, xbig, xsmall ) ) vram2(left:right, triy(2))= co !塗る vram3(left:right, triy(2))= 0 !塗る !中の線 if(dysmall .ge. 2) then do j=triy(2)-1, triy(1)+1, -1 left=int2( 0.5_8+ dmin1( xbig, xsmall, xbig-dxybig*2, xsmall-dxysmall*2 ) ) right=int2( 0.5_8+ dmax1( xbig, xsmall, xbig-dxybig*2, xsmall-dxysmall*2 ) ) vram2(left:right, j)= co !塗る vram3(left:right, j)= 0 !塗る xbig=xbig-dxybig*2 xsmall=xsmall-dxysmall*2 end do end if !最後の横一線 if(dybig .eq. dysmall) then d=dxybig else d=dxybig*2 end if left=int2( 0.5_8+ dmin1( xbig, xsmall, xbig-d, xsmall-dxysmall ) ) right=int2( 0.5_8+ dmax1( xbig, xsmall, xbig-d, xsmall-dxysmall ) ) vram2(left:right, triy(1))= co !塗る vram3(left:right, triy(1))= 0 !塗る end select end subroutine drawtriangle11 !(plx(0), ply(0)) - (ply(1), ply(1)) - ... - (plx(dots-1), ply(dots-1)) ! のポリゴンと四角リージョンの論理積をとる !cxbuf(spcbuf++), cybuf(spcbuf++) に atan2 でソートされた頂点が入る !ソートされた結果はポインタの配列 ptrcbuf(0:spcbuf-1) に入っている subroutine poly11() use common_variables implicit none integer(2), external :: cmp_function_poly11 real(8) poly_a(0:dots-1), poly_b(0:dots-1), poly_c(0:dots-1) real(8) poly_sign(0:dots-1) real(8) cx, cy, sign integer(2) j, k !四角リージョンの内側にあるポリゴンの頂点は採用する k=0 do j=0, dots-1 if( plx(j) .ge. 0.0_8-size_x/2 ) then if( plx(j) .le. size_x/2-1.0_8 ) then if( ply(j) .ge. 0.0_8-size_y/2 ) then if( ply(j) .le. size_y/2-1.0_8 ) then cxbuf(spcbuf)=plx(j) cybuf(spcbuf)=ply(j) spcbuf=spcbuf+1 k=k+1 end if end if end if end if end do if(k .eq. dots) goto 100 !すべての点が四角リージョンの内側にある場合、すぐにソート処理へ行く cx=0.0_8 cy=0.0_8 do j=0, dots-1 cx=cx+plx(j) cy=cy+ply(j) end do cx=cx/dots cy=cy/dots do j=0, dots-2 line_x0=plx(j) line_y0=ply(j) line_x1=plx(j+1) line_y1=ply(j+1) call getabc() poly_a(j)=line_a poly_b(j)=line_b poly_c(j)=line_c end do line_x0=plx(dots-1) line_y0=ply(dots-1) line_x1=plx(0) line_y1=ply(0) call getabc() poly_a(dots-1)=line_a poly_b(dots-1)=line_b poly_c(dots-1)=line_c poly_sign(0:dots-1)= poly_a(0:dots-1)*cx + poly_b(0:dots-1)*cy + poly_c(0:dots-1) !ポリゴンの内側にある四角リージョンの頂点は採用する do j=0, 3 do k=0, dots-1 sign= poly_a(k)*rctx(j) + poly_b(k)*rcty(j) + poly_c(k) if( poly_sign(k)*sign .lt. 0.0_8 ) goto 200 !異符号は採用しない end do cxbuf(spcbuf)=rctx(j) cybuf(spcbuf)=rcty(j) spcbuf=spcbuf+1 200 continue end do !ポリゴンの線と四角リージョンの線の交点が有効なものは採用する do j=0, dots-2 crx(0)=plx(j) cry(0)=ply(j) crx(1)=plx(j+1) cry(1)=ply(j+1) do k=0, 2 crx(2)=rctx(k) cry(2)=rcty(k) crx(3)=rctx(k+1) cry(3)=rcty(k+1) call cross() end do crx(2)=rctx(3) cry(2)=rcty(3) crx(3)=rctx(0) cry(3)=rcty(0) call cross() end do crx(0)=plx(dots-1) cry(0)=ply(dots-1) crx(1)=plx(0) cry(1)=ply(0) do k=0, 2 crx(2)=rctx(k) cry(2)=rcty(k) crx(3)=rctx(k+1) cry(3)=rcty(k+1) call cross() end do crx(2)=rctx(3) cry(2)=rcty(3) crx(3)=rctx(0) cry(3)=rcty(0) call cross() 100 continue !ソートする if(spcbuf .gt. 0) then do j=0, spcbuf-1 ptrcbuf(j)=j end do end if if(spcbuf .gt. 3) then cx=0.0_8 cy=0.0_8 do j=0, spcbuf-1 cx=cx+cxbuf(j) cy=cy+cybuf(j) end do cx=cx/spcbuf cy=cy/spcbuf do j=0, spcbuf-1 degree_cbuf(j)= datan2( cybuf(j)-cy, cxbuf(j)-cx ) end do CALL qsort(ptrcbuf, spcbuf, 2, cmp_function_poly11) end if end subroutine poly11 integer(2) function cmp_function_poly11(a1, a2) use common_variables implicit none integer(2) a1, a2 real(8) b1, b2 b1=degree_cbuf(a1) b2=degree_cbuf(a2) if( b1 .gt. b2 ) then cmp_function_poly11=int2(-1) return end if if( b1 .lt. b2 ) then cmp_function_poly11=int2(1) return end if cmp_function_poly11=int2(0) return end function cmp_function_poly11 subroutine poly21() use common_variables implicit none integer(2), external :: cmp_function_poly11 real(8) poly_a(0:dots-1), poly_b(0:dots-1), poly_c(0:dots-1) real(8) poly_sign(0:dots-1) real(8) cx, cy, sign integer(2) j, k real(8) rgnxmr, rgnxpr, rgnymr, rgnypr, x, y !四角リージョンの内側にあるポリゴンの頂点は採用する rgnxmr=plx(0) rgnxpr=rgnxmr rgnymr=ply(0) rgnypr=rgnymr k=0 do j=0, dots-1 x=plx(j) if( x .lt. rgnxmr ) rgnxmr=x if( x .gt. rgnxpr ) rgnxpr=x y=ply(j) if( y .lt. rgnymr ) rgnymr=y if( y .gt. rgnypr ) rgnypr=y if( x .ge. 0.0_8-size_x/2 ) then if( x .le. size_x/2-1.0_8 ) then if( y .ge. 0.0_8-size_y/2 ) then if( y .le. size_y/2-1.0_8 ) then cxbuf(spcbuf)=x cybuf(spcbuf)=y spcbuf=spcbuf+1 k=k+1 end if end if end if end if end do !リージョンが明らかに重ならないときは、何もしない if( 0.0_8+rgnxp .lt. size_x/2+rgnxmr ) goto 999 if( 0.0_8+rgnyp .lt. size_y/2+rgnymr ) goto 999 if( size_x/2+rgnxpr .lt. 0.0_8+rgnxm ) goto 999 if( size_y/2+rgnypr .lt. 0.0_8+rgnym ) goto 999 if(k .eq. dots) goto 100 !すべての点が四角リージョンの内側にある場合、すぐにソート処理へ行く cx=0.0_8 cy=0.0_8 do j=0, dots-1 cx=cx+plx(j) cy=cy+ply(j) end do cx=cx/dots cy=cy/dots do j=0, dots-2 line_x0=plx(j) line_y0=ply(j) line_x1=plx(j+1) line_y1=ply(j+1) call getabc() poly_a(j)=line_a poly_b(j)=line_b poly_c(j)=line_c end do line_x0=plx(dots-1) line_y0=ply(dots-1) line_x1=plx(0) line_y1=ply(0) call getabc() poly_a(dots-1)=line_a poly_b(dots-1)=line_b poly_c(dots-1)=line_c poly_sign(0:dots-1)= poly_a(0:dots-1)*cx + poly_b(0:dots-1)*cy + poly_c(0:dots-1) !ポリゴンの内側にある四角リージョンの頂点は採用する do j=0, 3 do k=0, dots-1 sign= poly_a(k)*rctx(j) + poly_b(k)*rcty(j) + poly_c(k) if( poly_sign(k)*sign .lt. 0.0_8 ) goto 200 !異符号は採用しない end do cxbuf(spcbuf)=rctx(j) cybuf(spcbuf)=rcty(j) spcbuf=spcbuf+1 200 continue end do !ポリゴンの線と四角リージョンの線の交点が有効なものは採用する do j=0, dots-2 crx(0)=plx(j) cry(0)=ply(j) crx(1)=plx(j+1) cry(1)=ply(j+1) do k=0, 2 crx(2)=rctx(k) cry(2)=rcty(k) crx(3)=rctx(k+1) cry(3)=rcty(k+1) call cross() end do crx(2)=rctx(3) cry(2)=rcty(3) crx(3)=rctx(0) cry(3)=rcty(0) call cross() end do crx(0)=plx(dots-1) cry(0)=ply(dots-1) crx(1)=plx(0) cry(1)=ply(0) do k=0, 2 crx(2)=rctx(k) cry(2)=rcty(k) crx(3)=rctx(k+1) cry(3)=rcty(k+1) call cross() end do crx(2)=rctx(3) cry(2)=rcty(3) crx(3)=rctx(0) cry(3)=rcty(0) call cross() 100 continue !ソートする if(spcbuf .gt. 0) then do j=0, spcbuf-1 ptrcbuf(j)=j end do end if if(spcbuf .gt. 3) then cx=0.0_8 cy=0.0_8 do j=0, spcbuf-1 cx=cx+cxbuf(j) cy=cy+cybuf(j) end do cx=cx/spcbuf cy=cy/spcbuf do j=0, spcbuf-1 degree_cbuf(j)= datan2( cybuf(j)-cy, cxbuf(j)-cx ) end do CALL qsort(ptrcbuf, spcbuf, 2, cmp_function_poly11) end if return 999 continue spcbuf=0 end subroutine poly21 subroutine displaydetail() use common_variables implicit none integer(2) j, k, j3, j4, j5, j9 real(8) x0, y0, z0, x1, y1, z1, aa, bb, cc, dd, x2, y2, z2 real(8) xx0(0:7), yy0(0:7), zz0(0:7), t(0:3), dz integer(2) n, ns real(8) sign, sign2, t1, sign3 integer(4) j1, k1, j2, j6, j7, k2, j8 integer(4) ix, iy, iz integer(4) ipiv(3) integer(2), external :: cmp_function_polygon !matrix = inverse transpose matrix0 逆行列を求める matrix=matrix0 call getrf(matrix, ipiv) call getri(matrix, ipiv) !matrix を転置する matrix=transpose(matrix) !面が何個表示されたか数える(デバッグ用)******* surfacecount=0 if(ptrcube .eq. 0) goto 999 !表示処理 !cubeoffset(xyz, 頂点番号, 面番号)(定数)→rotoffset(xyz, 頂点番号, 面番号)ベクトル回転する do j=0, 5 do k=0, 3 rotoffset(0:2,k,j)=matmul(matrix,cubeoffset(0:2,k,j)) end do end do do j=0, 5 !rot_abc(面番号) 各面について、a,b,cを計算する sur_x0=rotoffset(0,0,j) sur_y0=rotoffset(1,0,j) sur_z0=rotoffset(2,0,j) sur_x1=rotoffset(0,1,j) sur_y1=rotoffset(1,1,j) sur_z1=rotoffset(2,1,j) sur_x2=rotoffset(0,2,j) sur_y2=rotoffset(1,2,j) sur_z2=rotoffset(2,2,j) call getabcd() rot_a(j)=sur_a rot_b(j)=sur_b rot_c(j)=sur_c !signc(面番号) 立方体の真ん中の点について、6つの面に対する正負を計算 !ここでは真ん中の点は(0,0,0)なので !符号=a*x + b*y + c*z + d よって符号=dになる !dは直前のgetabcd()でsur_dに入っている signc(j)= sur_d end do !すべての頂点座標を計算する do j1=0, ptrcube-1 !各立方体の真ん中の点を回転 seev(0:2)=0.0_8+cube(0:2,j1)-eye(0:2) rot(0:2,j1)=matmul(matrix,seev) do j=0, 5 !sur(xyz, 頂点番号, 面番号, 通し番号)頂点の座標 do k=0, 3 sur(0:2, k, j, j1) = rot(0:2, j1) + rotoffset(0:2, k, j) end do !rot_d(面番号, 通し番号) dを計算する rot_d(j,j1)= -( rot_a(j)*sur(0,0,j,j1) + rot_b(j)*sur(1,0,j,j1) + rot_c(j)*sur(2,0,j,j1) ) !actcontact(面番号, 通し番号)互いに接している面は除外する ix=cube(0,j1)+dircontoffset(0,j) iy=cube(1,j1)+dircontoffset(1,j) iz=cube(2,j1)+dircontoffset(2,j) do k1=0, ptrcube-1 if( cube(0,k1).eq.ix ) then if( cube(1,k1).eq.iy ) then if( cube(2,k1).eq.iz ) then actcontact(j,j1)=.false. !除外する goto 100 end if end if end if end do actcontact(j,j1)=.true. !採用する 100 continue end do end do endofsortptr=0 do j1=0, ptrcube-1 !sur(xyz, 頂点番号, 面番号, 通し番号) !1ヶの立方体の座標の中で、どれかがカットラインより前に有れば採用する可能性がある do j=0, 5 do k=0, 3 if( sur(2,k,j,j1) .gt. cutline2 ) goto 210 end do end do !すべての座標がカットラインより後ろにあった do j=0, 5 act(j,j1)=.false. end do goto 200 210 continue !ソート用ポインタに登録 sortptr(endofsortptr)=j1 endofsortptr=endofsortptr+1 !act(面番号, 通し番号) !actcontactがfalseのときは無条件でfalse !視点(0,0,-eyeoffset)に対して隠れている3つの面を除外する do j=0, 5 act(j,j1)=actcontact(j,j1) if( signc(j) * ( rot_c(j)*-eyeoffset + rot_d(j,j1) ) .gt. 0.0_8 ) act(j,j1)=.false. !正負が合っていれば、隠れ面 end do 200 continue end do !影が何個表示されたか数える(デバッグ用)******* shadowcount=0 !影モードの準備処理(表示する立方体が無いときは、飛ばして良し) if( endofsortptr .gt. 0 ) then !光源を回転 rotray(0:2)=matmul(matrix,ray(0:2)) do j=0, 5 !actshadow(面番号) actshadow(j)=.true. !rotoffset(xyz, 頂点番号, 面番号) !各面の真ん中の点から光源の0.1倍のベクトルを伸ばした座標を計算する x0=( rotoffset(0,0,j)+rotoffset(0,1,j)+rotoffset(0,2,j)+rotoffset(0,3,j) ) / 4 + rotray(0)/10 y0=( rotoffset(1,0,j)+rotoffset(1,1,j)+rotoffset(1,2,j)+rotoffset(1,3,j) ) / 4 + rotray(1)/10 z0=( rotoffset(2,0,j)+rotoffset(2,1,j)+rotoffset(2,2,j)+rotoffset(2,3,j) ) / 4 + rotray(2)/10 !この立方体の真ん中の点(0,0,0)に対する各面の正/負と比較し、 !合っていなければtrueの可能性有り、合っていればfalse do k=0, 5 sign= rot_a(k)*x0 + rot_b(k)*y0 + rot_c(k)*z0 + signc(k) !"rot_d(k)"はsignc(k)と同じである if( (dabs(sign) .gt. 0.00001_8) .and. (sign * signc(k) .lt. 0.0_8) ) goto 300 !合っていないので採用される可能性ある end do !全部合っているということは、光源ベクトルの方向は、この面から立方体の内側へ向かっている actshadow(j)=.false. 300 continue end do !centerpoint(xyz, 面番号, 通し番号) 各面の真ん中の点 !sur(xyz, 頂点番号, 面番号, 通し番号)の各頂点を足して4で割る centerpoint(0:2, 0:5, 0:ptrcube-1)= ( sur(0:2, 0, 0:5, 0:ptrcube-1)+sur(0:2, 1, 0:5, 0:ptrcube-1)+sur(0:2, 2, 0:5, 0:ptrcube-1)+sur(0:2, 3, 0:5, 0:ptrcube-1) )/4 end if !ポリゴンを表示する if( endofsortptr .gt. 0 ) then !視点(0,0,-eyeoffset)からの距離を計算 distance(sortptr(0:endofsortptr-1))= rot(0,sortptr(0:endofsortptr-1))**2 + rot(1,sortptr(0:endofsortptr-1))**2 + (rot(2,sortptr(0:endofsortptr-1))+eyeoffset)**2 !ソートする CALL qsort(sortptr, endofsortptr, 4, cmp_function_polygon) !表示する do j1=0, endofsortptr-1 k1=sortptr(j1) do j=0, 5 if( act(j,k1) ) then xx0(0:3)=sur(0, 0:3, j, k1) yy0(0:3)=sur(1, 0:3, j, k1) zz0(0:3)=sur(2, 0:3, j, k1) if( (zz0(0) .le. cutline2) .and. (zz0(1) .le. cutline2) .and. (zz0(2) .le. cutline2) .and. (zz0(3) .le. cutline2) ) then goto 310 !すべての頂点がカットラインの後ろにあるため、何もしない end if !どれかの頂点がカットラインより前にある xx0(4:7)=xx0(0:3) yy0(4:7)=yy0(0:3) zz0(4:7)=zz0(0:3) do j4=0, 3 if(zz0(j4) .le. cutline2 ) then !カットラインより後ろにある !どれかは前にあり、どれかは後ろにあるので、3次元座標を切り取る if(zz0(0) .le. cutline2 ) then j9=0 do while( zz0(j9) .le. cutline2 ) j9=j9+1 end do !切り取る線 zz0(j9-1) - zz0(j9) j5=j9 do while( zz0(j5) .gt. cutline2 ) !前にある座標 j5=j5+1 end do !切り取る線 zz0(j5-1) - zz0(j5) else j5=0 do while( zz0(j5) .gt. cutline2 ) j5=j5+1 end do j9=j5 do while( zz0(j9) .le. cutline2 ) j9=j9+1 end do !切り取る線 zz0(j9-1) - zz0(j9) j5=j9 do while( zz0(j5) .gt. cutline2 ) !前にある座標 j5=j5+1 end do !切り取る線 zz0(j5-1) - zz0(j5) end if !zz0(j9-1)とzz0(j9)の切り取り点, 点zz0(j9)〜zz0(j5-1), zz0(j5-1)とzz0(j5)の切り取り点 dz= zz0(j9)-zz0(j9-1) if( dabs(dz) .lt. 0.0001_8 ) goto 310 !zz0(j9-1)とzz0(j9)が近い場合、何もしない dz= ( cutline2-zz0(j9-1) ) / dz xx0(j9-1)= xx0(j9-1) + ( xx0(j9)-xx0(j9-1) ) * dz yy0(j9-1)= yy0(j9-1) + ( yy0(j9)-yy0(j9-1) ) * dz zz0(j9-1)= 0.0_8+cutline2 dz= zz0(j5)-zz0(j5-1) if( dabs(dz) .lt. 0.0001_8 ) goto 310 !zz0(j5-1)とzz0(j5)が近い場合、何もしない dz= ( cutline2-zz0(j5-1) ) / dz xx0(j5)= xx0(j5-1) + ( xx0(j5)-xx0(j5-1) ) * dz yy0(j5)= yy0(j5-1) + ( yy0(j5)-yy0(j5-1) ) * dz zz0(j5)= 0.0_8+cutline2 !投影する zz0(j9-1:j5) = (screen+eyeoffset)/(zz0(j9-1:j5)+eyeoffset) ns= j5 - (j9-1) + 1 polydata(0:ns-1).wx = xx0(j9-1:j5)*zz0(j9-1:j5)*zoom polydata(0:ns-1).wy = yy0(j9-1:j5)*zz0(j9-1:j5)*zoom goto 320 end if end do !4点すべてカットラインより前にあった !投影する zz0(0:3) = (screen+eyeoffset)/(zz0(0:3)+eyeoffset) polydata(0:3).wx = xx0(0:3)*zz0(0:3)*zoom polydata(0:3).wy = yy0(0:3)*zz0(0:3)*zoom ns=4 320 continue surfacecount=surfacecount+1 !影の表示 aa= rot_a(j) bb= rot_b(j) cc= rot_c(j) dd= rot_d(j, k1) !この面番号jの面に対し、視点(0,0,-eyeoffset)の正/負を調べる sign= cc*-eyeoffset + dd !このjの面の頂点番号0から、光源ベクトルを伸ばした座標を計算する x0= sur(0, 0, j, k1) + rotray(0) y0= sur(1, 0, j, k1) + rotray(1) z0= sur(2, 0, j, k1) + rotray(2) !その正/負を調べる sign2= aa*x0 + bb*y0 + cc*z0 + dd !これが0に近い(面と光源が平行)とき、この面は全部影にする !また、符号が合っている場合、光源に対して面の裏側を見ていることになるので、この面は全部影になる if( (dabs(sign2) .lt. 0.00001_8) .or. (sign * sign2 .ge. 0.0_8) ) then !面と光源が平行であるか、符号が合っている call drawpolygon11( cubecolor(j) .and. shadowcolor, ns ) !面番号に対応した影の色にする if( afterpolydots .ge. 3 ) then call vram_and_or() shadowcount=shadowcount+1 end if goto 400 !この面の処理終わり else !合っていない場合、以下の処理によってこの面は影で上書きされる call drawpolygon11( cubecolor(j), ns ) !面番号に対応した影でない色にする if(afterpolydots .lt. 3) goto 400 !影で上書きされる予定のjの面が実際に表示されなかった場合、この面の処理終わり end if !分母が0に近いとき、影の頂点は計算不能 t1 = -aa*rotray(0)-bb*rotray(1)-cc*rotray(2) if( dabs(t1) .lt. 0.00001 ) goto 410 !登録されたすべての立方体の6面が影の発生原因になる可能性ある do j2=0, ptrcube-1 !通し番号が自分自身でないものについて処理する if(j2.ne.k1) then !このj2の立方体の真ん中の点に対する符号を見る !rot(xyz, 通し番号) 回転後の真ん中の点 sign= aa*rot(0,j2) + bb*rot(1,j2) + cc*rot(2,j2) + dd !このjの面の頂点番号0から、光源ベクトルを伸ばした座標の正/負はsign2に入っている if(sign * sign2 .ge. 0.0_8 ) goto 500 !符号が合っているときは影の原因にならないので除外する do j3=0, 5 !actshadow(面番号)がtrueのものについて処理する !actcontact(面番号, 通し番号)がfalseのときは無条件でfalse if( actshadow(j3) .and. actcontact(j3,j2) ) then !このj3の面の真ん中の点の符号を見る !centerpoint(xyz, 面番号, 通し番号) sign= aa*centerpoint(0,j3,j2) + bb*centerpoint(1,j3,j2) + cc*centerpoint(2,j3,j2) + dd if( dabs(sign) .lt. 0.00001 ) goto 510 !jの面の延長上にあるこの面は影の原因にならない !j,k1の面の頂点とj2,j3の面の頂点が一致しているか調べる j4=0 do j5=0, 3 do j9=0, 3 if( dabs(sur(0, j5, j, k1) - sur(0, j9, j3, j2)) + dabs(sur(1, j5, j, k1) - sur(1, j9, j3, j2)) + dabs(sur(2, j5, j, k1) - sur(2, j9, j3, j2)) .lt. 0.00001 ) then j4=j4+1 x2=sur(0,j5,j,k1) y2=sur(1,j5,j,k1) z2=sur(2,j5,j,k1) end if end do end do if(j4 .ne. 1) goto 600 !1点で接している場合以外は、見逃す !1点で接している場合、「黒点」の問題が存在する可能性がある !接している点は(x2, y2, z2)に入っている !この点から光源ベクトル/10を伸ばす x2=x2+rotray(0)/10 y2=y2+rotray(1)/10 z2=z2+rotray(2)/10 do j4=0, 5 sign3= rot_a(j4)*x2 + rot_b(j4)*y2 + rot_c(j4)*z2 + rot_d(j4,k1) if( sign3*signc(j4) .lt. 0.0_8 ) goto 510 !k1の立方体の外側へ向かっているので、これは影の原因ではない end do 600 continue !次の方程式をtについて解く !x == x0 + (x1 - x0)*t !y == y0 + (y1 - y0)*t !z == z0 + (z1 - z0)*t !a*x + b*y + c*z + d == 0 !結果は !t = (d + a x0 + b y0 + c z0) ! / (a x0 - a x1 + b y0 - b y1 + c z0 - c z1) !sur(xyz, 頂点番号, 面番号, 通し番号) xx0(0:3)=sur(0, 0:3, j3, j2) yy0(0:3)=sur(1, 0:3, j3, j2) zz0(0:3)=sur(2, 0:3, j3, j2) t(0:3) = (dd + aa*xx0(0:3) + bb*yy0(0:3) + cc*zz0(0:3)) / t1 !投影する zz0(0:3)=zz0(0:3)+rotray(2)*t(0:3) do j4=0, 3 if(zz0(j4) .le. cutline2 ) then !カットラインより後ろにある if( dmax1(zz0(0), zz0(1), zz0(2), zz0(3)) .le. cutline2 ) goto 510 !全部後ろにある場合、何もしない !どれかは前にあり、どれかは後ろにあるので、影の3次元座標を切り取る zz0(4:7)=zz0(0:3) xx0(0:3)=xx0(0:3)+rotray(0)*t(0:3) yy0(0:3)=yy0(0:3)+rotray(1)*t(0:3) xx0(4:7)=xx0(0:3) yy0(4:7)=yy0(0:3) if(zz0(0) .le. cutline2 ) then j9=0 do while( zz0(j9) .le. cutline2 ) j9=j9+1 end do !切り取る線 zz0(j9-1) - zz0(j9) j5=j9 do while( zz0(j5) .gt. cutline2 ) !前にある座標 j5=j5+1 end do !切り取る線 zz0(j5-1) - zz0(j5) else j5=0 do while( zz0(j5) .gt. cutline2 ) j5=j5+1 end do j9=j5 do while( zz0(j9) .le. cutline2 ) j9=j9+1 end do !切り取る線 zz0(j9-1) - zz0(j9) j5=j9 do while( zz0(j5) .gt. cutline2 ) !前にある座標 j5=j5+1 end do !切り取る線 zz0(j5-1) - zz0(j5) end if !zz0(j9-1)とzz0(j9)の切り取り点, 点zz0(j9)〜zz0(j5-1), zz0(j5-1)とzz0(j5)の切り取り点 dz= zz0(j9)-zz0(j9-1) if( dabs(dz) .lt. 0.0001_8 ) goto 510 !zz0(j9-1)とzz0(j9)が近い場合、何もしない dz= ( cutline2-zz0(j9-1) ) / dz xx0(j9-1)= xx0(j9-1) + ( xx0(j9)-xx0(j9-1) ) * dz yy0(j9-1)= yy0(j9-1) + ( yy0(j9)-yy0(j9-1) ) * dz zz0(j9-1)= 0.0_8+cutline2 dz= zz0(j5)-zz0(j5-1) if( dabs(dz) .lt. 0.0001_8 ) goto 510 !zz0(j5-1)とzz0(j5)が近い場合、何もしない dz= ( cutline2-zz0(j5-1) ) / dz xx0(j5)= xx0(j5-1) + ( xx0(j5)-xx0(j5-1) ) * dz yy0(j5)= yy0(j5-1) + ( yy0(j5)-yy0(j5-1) ) * dz zz0(j5)= 0.0_8+cutline2 zz0(j9-1:j5) = (screen+eyeoffset)/(zz0(j9-1:j5)+eyeoffset) n= j5 - (j9-1) + 1 polydata(0:n-1).wx = xx0(j9-1:j5)*zz0(j9-1:j5)*zoom polydata(0:n-1).wy = yy0(j9-1:j5)*zz0(j9-1:j5)*zoom goto 430 end if end do !4点すべてカットラインより前にあった zz0(0:3) = (screen+eyeoffset)/(zz0(0:3)+eyeoffset) polydata(0:3).wx = (xx0(0:3) + rotray(0)*t(0:3))*zz0(0:3)*zoom polydata(0:3).wy = (yy0(0:3) + rotray(1)*t(0:3))*zz0(0:3)*zoom n=4 430 continue call drawpolygon21( n ) if( afterpolydots .ge. 3 ) shadowcount=shadowcount+1 !3角形以上のとき、採用された end if 510 continue end do 500 continue end if end do !影の原因になる可能性のあるすべての立方体を調べた 410 continue call vram_and_or() 400 continue end if 310 continue end do end do end if 999 continue end subroutine displaydetail subroutine displaycube() use common_variables implicit none integer(2) j, k, j3, j4, j5, j9 real(8) x0, y0, z0, x1, y1, z1, aa, bb, cc, dd real(8) xx0(0:7), yy0(0:7), zz0(0:7), t(0:3), dz integer(2) n, ns real(8) sign, sign2, t1 integer(4) j1, k1, j2, j6, j7, k2, j8, l integer(4) oldk1 integer(4) ptrcapture, beforeptrcapture, nextptrcapture, dx, dy, c, p, p1 integer(4) ix, iy, iz integer(4) ipiv(3) logical(2) reg integer(2), external :: cmp_function_polygon !matrix = inverse transpose matrix0 逆行列を求める matrix=matrix0 call getrf(matrix, ipiv) call getri(matrix, ipiv) !matrix を転置する matrix=transpose(matrix) !面が何個表示されたか数える(デバッグ用)******* surfacecount=0 ptrcapture=0 endofcutangles=0 if(ptrcube .eq. 0) goto 999 !表示処理 !cubeoffset(xyz, 頂点番号, 面番号)(定数)→rotoffset(xyz, 頂点番号, 面番号)ベクトル回転する do j=0, 5 do k=0, 3 rotoffset(0:2,k,j)=matmul(matrix,cubeoffset(0:2,k,j)) end do end do do j=0, 5 !rot_abc(面番号) 各面について、a,b,cを計算する sur_x0=rotoffset(0,0,j) sur_y0=rotoffset(1,0,j) sur_z0=rotoffset(2,0,j) sur_x1=rotoffset(0,1,j) sur_y1=rotoffset(1,1,j) sur_z1=rotoffset(2,1,j) sur_x2=rotoffset(0,2,j) sur_y2=rotoffset(1,2,j) sur_z2=rotoffset(2,2,j) call getabcd() rot_a(j)=sur_a rot_b(j)=sur_b rot_c(j)=sur_c !signc(面番号) 立方体の真ん中の点について、6つの面に対する正負を計算 !ここでは真ん中の点は(0,0,0)なので !符号=a*x + b*y + c*z + d よって符号=dになる !dは直前のgetabcd()でsur_dに入っている signc(j)= sur_d end do !すべての頂点座標を計算する do j1=0, ptrcube-1 !各立方体の真ん中の点を回転 seev(0:2)=0.0_8+cube(0:2,j1)-eye(0:2) rot(0:2,j1)=matmul(matrix,seev) do j=0, 5 !sur(xyz, 頂点番号, 面番号, 通し番号)頂点の座標 do k=0, 3 sur(0:2, k, j, j1) = rot(0:2, j1) + rotoffset(0:2, k, j) end do !rot_d(面番号, 通し番号) dを計算する rot_d(j,j1)= -( rot_a(j)*sur(0,0,j,j1) + rot_b(j)*sur(1,0,j,j1) + rot_c(j)*sur(2,0,j,j1) ) !actcontact(面番号, 通し番号)互いに接している面は除外する ix=cube(0,j1)+dircontoffset(0,j) iy=cube(1,j1)+dircontoffset(1,j) iz=cube(2,j1)+dircontoffset(2,j) do k1=0, ptrcube-1 if( cube(0,k1).eq.ix ) then if( cube(1,k1).eq.iy ) then if( cube(2,k1).eq.iz ) then actcontact(j,j1)=.false. !除外する goto 100 end if end if end if end do actcontact(j,j1)=.true. !採用する 100 continue end do end do endofcutangles=0 endofsortptr=0 do j1=0, ptrcube-1 if( rot(2,j1) .gt. cutline+sqr3d2 ) then !立方体の中心が cutline+sqr(3)/2 よりも前にある場合、登録する !act(面番号, 通し番号) !actcontactがfalseのときは無条件でfalse !視点(0,0,-eyeoffset)に対して隠れている3つの面を除外する do j=0, 5 act(j,j1)=actcontact(j,j1) if( signc(j) * ( rot_c(j)*-eyeoffset + rot_d(j,j1) ) .gt. 0.0_8 ) act(j,j1)=.false. !正負が合っていれば、隠れ面 end do ptrcut(0:5, j1)=-1 !カットライン処理とは無関係のため、ポインタをリセットする goto 201 end if if( rot(2,j1) .le. cutline-sqr3d2 ) goto 200 !立方体の中心が cutline-sqr(3)/2 よりも後ろにある場合、登録しない !立方体の中心がカットライン付近にある場合 !act(面番号, 通し番号) !actcontactがfalseのときは無条件でfalse !視点(0,0,-eyeoffset)に対して隠れている3つの面を除外する do j=0, 5 act(j,j1)=actcontact(j,j1) if( signc(j) * ( rot_c(j)*-eyeoffset + rot_d(j,j1) ) .gt. 0.0_8 ) act(j,j1)=.false. !正負が合っていれば、隠れ面 end do reg=.false. do j=0, 5 if( act(j,j1) ) then xx0(0:3)=sur(0, 0:3, j, j1) yy0(0:3)=sur(1, 0:3, j, j1) zz0(0:3)=sur(2, 0:3, j, j1) if( (zz0(0) .le. cutline) .and. (zz0(1) .le. cutline) .and. (zz0(2) .le. cutline) .and. (zz0(3) .le. cutline) ) then act(j,j1)= .false. !すべての頂点がカットラインの後ろにあるため、登録しない goto 210 end if if( (zz0(0) .gt. cutline) .and. (zz0(1) .gt. cutline) .and. (zz0(2) .gt. cutline) .and. (zz0(3) .gt. cutline) ) then !すべての頂点がカットラインの前にあるため、登録する !ポインタをリセットし、通常の4角形を投影させる ptrcut(j, j1)=-1 reg=.true. goto 210 end if !どれかの頂点がカットラインより前にあり、どれかは後ろにある xx0(4:7)=xx0(0:3) yy0(4:7)=yy0(0:3) zz0(4:7)=zz0(0:3) do j4=0, 3 if(zz0(j4) .le. cutline ) then !カットラインより後ろにある !どれかは前にあり、どれかは後ろにあるので、3次元座標を切り取る if(zz0(0) .le. cutline ) then j9=0 do while( zz0(j9) .le. cutline ) j9=j9+1 end do !切り取る線 zz0(j9-1) - zz0(j9) j5=j9 do while( zz0(j5) .gt. cutline ) !前にある座標 j5=j5+1 end do !切り取る線 zz0(j5-1) - zz0(j5) else j5=0 do while( zz0(j5) .gt. cutline ) j5=j5+1 end do j9=j5 do while( zz0(j9) .le. cutline ) j9=j9+1 end do !切り取る線 zz0(j9-1) - zz0(j9) j5=j9 do while( zz0(j5) .gt. cutline ) !前にある座標 j5=j5+1 end do !切り取る線 zz0(j5-1) - zz0(j5) end if !zz0(j9-1)とzz0(j9)の切り取り点, 点zz0(j9)〜zz0(j5-1), zz0(j5-1)とzz0(j5)の切り取り点 dz= zz0(j9)-zz0(j9-1) if( dabs(dz) .lt. 0.0001_8 ) goto 200 !zz0(j9-1)とzz0(j9)が近い場合、何もしない dz= ( cutline-zz0(j9-1) ) / dz xx0(j9-1)= xx0(j9-1) + ( xx0(j9)-xx0(j9-1) ) * dz yy0(j9-1)= yy0(j9-1) + ( yy0(j9)-yy0(j9-1) ) * dz zz0(j9-1)= 0.0_8+cutline dz= zz0(j5)-zz0(j5-1) if( dabs(dz) .lt. 0.0001_8 ) goto 200 !zz0(j5-1)とzz0(j5)が近い場合、何もしない dz= ( cutline-zz0(j5-1) ) / dz xx0(j5)= xx0(j5-1) + ( xx0(j5)-xx0(j5-1) ) * dz yy0(j5)= yy0(j5-1) + ( yy0(j5)-yy0(j5-1) ) * dz zz0(j5)= 0.0_8+cutline !投影する zz0(j9-1:j5) = (screen+eyeoffset)/(zz0(j9-1:j5)+eyeoffset) ns= j5 - (j9-1) + 1 polydata(0:ns-1).wx = xx0(j9-1:j5)*zz0(j9-1:j5)*zoom polydata(0:ns-1).wy = yy0(j9-1:j5)*zz0(j9-1:j5)*zoom if(endofcutangles .ge. maxcutangles-ns*2-1) then result=messageboxqq('カットライン処理領域が足りません'C, 'Neo cubes'C, MB$OK) goto 999 end if !ポインタを登録 ptrcut(j, j1)=endofcutangles cutangles(endofcutangles)=ns+0.0_8 do k=0, ns-1 cutangles(endofcutangles+1+k*2+0)=polydata(k).wx cutangles(endofcutangles+1+k*2+1)=polydata(k).wy end do endofcutangles=endofcutangles+1+ns*2 reg=.true. goto 210 end if end do !ここはバグ result=messageboxqq('BUG カットライン処理'C, 'Neo cubes'C, MB$OK) 210 continue end if end do if( .not. reg ) goto 200 !0〜5の面番号すべてで登録されない場合、ソートポインタにも登録しない 201 continue !ソート用ポインタに登録 sortptr(endofsortptr)=j1 endofsortptr=endofsortptr+1 200 continue end do !影が何個表示されたか数える(デバッグ用)******* shadowcount=0 !影モードの準備処理(表示する立方体が無いときは、飛ばして良し) if( (endofsortptr .gt. 0) .and. shadowmode) then !光源を回転 rotray(0:2)=matmul(matrix,ray(0:2)) do j=0, 5 !actshadow(面番号) actshadow(j)=.true. !rotoffset(xyz, 頂点番号, 面番号) !各面の真ん中の点から光源の0.1倍のベクトルを伸ばした座標を計算する x0=( rotoffset(0,0,j)+rotoffset(0,1,j)+rotoffset(0,2,j)+rotoffset(0,3,j) ) / 4 + rotray(0)/10 y0=( rotoffset(1,0,j)+rotoffset(1,1,j)+rotoffset(1,2,j)+rotoffset(1,3,j) ) / 4 + rotray(1)/10 z0=( rotoffset(2,0,j)+rotoffset(2,1,j)+rotoffset(2,2,j)+rotoffset(2,3,j) ) / 4 + rotray(2)/10 !この立方体の真ん中の点(0,0,0)に対する各面の正/負と比較し、 !合っていなければtrueの可能性有り、合っていればfalse do k=0, 5 sign= rot_a(k)*x0 + rot_b(k)*y0 + rot_c(k)*z0 + signc(k) !"rot_d(k)"はsignc(k)と同じである if( (dabs(sign) .gt. 0.00001_8) .and. (sign * signc(k) .lt. 0.0_8) ) goto 300 !合っていないので採用される可能性ある end do !全部合っているということは、光源ベクトルの方向は、この面から立方体の内側へ向かっている actshadow(j)=.false. 300 continue end do !centerpoint(xyz, 面番号, 通し番号) 各面の真ん中の点 !sur(xyz, 頂点番号, 面番号, 通し番号)の各頂点を足して4で割る centerpoint(0:2, 0:5, 0:ptrcube-1)= ( sur(0:2, 0, 0:5, 0:ptrcube-1)+sur(0:2, 1, 0:5, 0:ptrcube-1)+sur(0:2, 2, 0:5, 0:ptrcube-1)+sur(0:2, 3, 0:5, 0:ptrcube-1) )/4 end if !ポリゴンを表示する if( endofsortptr .gt. 0 ) then !視点(0,0,-eyeoffset)からの距離を計算 distance(sortptr(0:endofsortptr-1))= rot(0,sortptr(0:endofsortptr-1))**2 + rot(1,sortptr(0:endofsortptr-1))**2 + (rot(2,sortptr(0:endofsortptr-1))+eyeoffset)**2 !ソートする CALL qsort(sortptr, endofsortptr, 4, cmp_function_polygon) !同じdを持つ平面をグループにする ppgroup=0 pgroupforcube=0 ppsort=0 !キャプチャー領域を指す予定のsortc(maxcubes*6)へのポインタ(ソートされた順に並んでいる) do j1=0, endofsortptr-1 k1=sortptr(j1) do j=0, 5 if( act(j,k1) ) then dd= rot_d(j,k1) j2=0 do while (j2 .lt. ppgroup) if( j .eq. groupforsurface(j2) ) then if( dabs(dd-groupd(j2)) .lt. 0.00001_8 ) then !同じ面番号で同じdを持つ j6=endofnext(j2) endofnext(j2)=pgroupforcube nextptr(j6)=pgroupforcube nextptr(pgroupforcube)=-1 groupforserial(pgroupforcube)=k1 !通し番号 sortc(ppsort)=pgroupforcube ppsort=ppsort+1 pgroupforcube=pgroupforcube+1 goto 350 end if end if j2=j2+1 end do !新しいdの定義 groupd(ppgroup)=dd ptrgroup(ppgroup)=pgroupforcube groupforserial(pgroupforcube)=k1 !通し番号 endofnext(ppgroup)=pgroupforcube nextptr(pgroupforcube)=-1 sortc(ppsort)=pgroupforcube ppsort=ppsort+1 pgroupforcube=pgroupforcube+1 groupforsurface(ppgroup)=j !面番号 ppgroup=ppgroup+1 end if 350 continue end do end do !表示する if( ppgroup .gt. 0 ) then ptrcapture=0 do j1=0, ppgroup-1 identity(0:ptrcube-1)=.true. !このグループに対する影の処理を制限するための変数 j=groupforsurface(j1) !面番号 beforeptrcapture=ptrcapture c=0 isrgnsetted=.false. p=ptrgroup(j1) j2=0 do while (p .ne. -1) k1=groupforserial(p) !通し番号 if(j2 .eq. 0) oldk1=k1 !このグループ全体を代表して最初の面の通し番号を取る identity(k1)=.false. !このグループに所属するすべての面は影の発生原因としない surfacecount=surfacecount+1 p1=ptrcut(j,k1) if( p1 .eq. -1 ) then !元の4角形を採用する !投影する !sur(xyz, 頂点番号, 面番号, 通し番号) do k=0, 3 z0=(screen+eyeoffset)/(sur(2, k, j, k1)+eyeoffset) polydata(k).wx=sur(0, k, j, k1)*z0*zoom polydata(k).wy=sur(1, k, j, k1)*z0*zoom end do call drawpolygon( cubecolor(j), 4 ) !面番号に対応した影でない色にする else !カットライン付近で切り取られた面を採用する ns=int2(cutangles(p1)) do k=0, ns-1 polydata(k).wx=cutangles(p1+1+k*2+0) polydata(k).wy=cutangles(p1+1+k*2+1) end do call drawpolygon( cubecolor(j), ns ) !面番号に対応した影でない色にする end if if( afterpolydots .ge. 3 ) then c=1 !3角形以上が表示された dx=rgnxp-rgnxm+1 dy=rgnyp-rgnym+1 nextptrcapture= ptrcapture + 4 + dx*dy*2 !キャプチャー領域のサイズはリージョンのサイズ*2とする if( nextptrcapture .ge. maxcapture ) then result=messageboxqq('キャプチャー領域が足りません'C, 'Neo cubes'C, MB$OK) goto 999 end if groupforserial(p)=ptrcapture !通し番号へのポインタをキャプチャー領域へのポインタに書き換える capture(ptrcapture+0)=rgnxm capture(ptrcapture+1)=rgnym capture(ptrcapture+2)=dx capture(ptrcapture+3)=dy ptrcapture=ptrcapture+4 do j3=rgnym, rgnyp capture(ptrcapture:ptrcapture+dx-1)=vram3(rgnxm:rgnxm+dx-1,j3) !ここではビットマスクを転送する ptrcapture=ptrcapture+dx end do ptrcapture=nextptrcapture else groupforserial(p)=-1 !何も表示しないときは、ポインタを無効にする end if p=nextptr(p) j2=1 end do if( shadowmode .and. (c .eq. 1) ) then !3角形が1度以上表示されたことがある場合、 !影を表示する k1=oldk1 aa= rot_a(j) bb= rot_b(j) cc= rot_c(j) dd= rot_d(j, k1) !このグループの面に対し、視点(0,0,-eyeoffset)の正/負を調べる sign= cc*-eyeoffset + dd !この面の頂点番号0から、光源ベクトルを伸ばした座標を計算する x0= sur(0, 0, j, k1) + rotray(0) y0= sur(1, 0, j, k1) + rotray(1) z0= sur(2, 0, j, k1) + rotray(2) !その正/負を調べる sign2= aa*x0 + bb*y0 + cc*z0 + dd !これが0に近い(面と光源が平行)とき、この面は全部影にする !また、符号が合っている場合、光源に対して面の裏側を見ていることになるので、この面は全部影になる if( (dabs(sign2) .lt. 0.00001_8) .or. (sign * sign2 .ge. 0.0_8) ) then !面と光源が平行であるか、符号が合っている if( isrgnsetted ) then vram2(rgnxmgroup:rgnxpgroup,rgnymgroup:rgnypgroup)=( vram2(rgnxmgroup:rgnxpgroup,rgnymgroup:rgnypgroup) .and. shadowcolor ) shadowcount=shadowcount+1 end if goto 400 !この面の処理終わり end if !合っていない場合、以下の処理によってこの面は影で上書きされる !分母が0に近いとき、影の頂点は計算不能 t1 = -aa*rotray(0)-bb*rotray(1)-cc*rotray(2) if( dabs(t1) .lt. 0.00001 ) goto 400 !登録されたすべての立方体の6面が影の発生原因になる可能性ある do j2=0, ptrcube-1 !通し番号がこのグループ自身でないものについて処理する if( identity(j2) ) then !このj2の立方体の真ん中の点に対する符号を見る !rot(xyz, 通し番号) 回転後の真ん中の点 sign= aa*rot(0,j2) + bb*rot(1,j2) + cc*rot(2,j2) + dd !このjの面の頂点番号0から、光源ベクトルを伸ばした座標の正/負はsign2に入っている if(sign * sign2 .ge. 0.0_8 ) goto 500 !符号が合っているときは影の原因にならないので除外する do j3=0, 5 !actshadow(面番号)がtrueのものについて処理する !actcontact(面番号, 通し番号)がfalseのときは無条件でfalse if( actshadow(j3) .and. actcontact(j3,j2) ) then !このj3の面の真ん中の点の符号を見る !centerpoint(xyz, 面番号, 通し番号) sign= aa*centerpoint(0,j3,j2) + bb*centerpoint(1,j3,j2) + cc*centerpoint(2,j3,j2) + dd if( dabs(sign) .lt. 0.00001 ) goto 510 !jの面の延長上にあるこの面は影の原因にならない !次の方程式をtについて解く !x == x0 + (x1 - x0)*t !y == y0 + (y1 - y0)*t !z == z0 + (z1 - z0)*t !a*x + b*y + c*z + d == 0 !結果は !t = (d + a x0 + b y0 + c z0) ! / (a x0 - a x1 + b y0 - b y1 + c z0 - c z1) !sur(xyz, 頂点番号, 面番号, 通し番号) xx0(0:3)=sur(0, 0:3, j3, j2) yy0(0:3)=sur(1, 0:3, j3, j2) zz0(0:3)=sur(2, 0:3, j3, j2) t(0:3) = (dd + aa*xx0(0:3) + bb*yy0(0:3) + cc*zz0(0:3)) / t1 !投影する zz0(0:3)=zz0(0:3)+rotray(2)*t(0:3) do j4=0, 3 if(zz0(j4) .le. cutline ) then !カットラインより後ろにある if( dmax1(zz0(0), zz0(1), zz0(2), zz0(3)) .le. cutline ) goto 510 !全部後ろにある場合、何もしない !どれかは前にあり、どれかは後ろにあるので、影の3次元座標を切り取る zz0(4:7)=zz0(0:3) xx0(0:3)=xx0(0:3)+rotray(0)*t(0:3) yy0(0:3)=yy0(0:3)+rotray(1)*t(0:3) xx0(4:7)=xx0(0:3) yy0(4:7)=yy0(0:3) if(zz0(0) .le. cutline ) then j9=0 do while( zz0(j9) .le. cutline ) j9=j9+1 end do !切り取る線 zz0(j9-1) - zz0(j9) j5=j9 do while( zz0(j5) .gt. cutline ) !前にある座標 j5=j5+1 end do !切り取る線 zz0(j5-1) - zz0(j5) else j5=0 do while( zz0(j5) .gt. cutline ) j5=j5+1 end do j9=j5 do while( zz0(j9) .le. cutline ) j9=j9+1 end do !切り取る線 zz0(j9-1) - zz0(j9) j5=j9 do while( zz0(j5) .gt. cutline ) !前にある座標 j5=j5+1 end do !切り取る線 zz0(j5-1) - zz0(j5) end if !zz0(j9-1)とzz0(j9)の切り取り点, 点zz0(j9)〜zz0(j5-1), zz0(j5-1)とzz0(j5)の切り取り点 dz= zz0(j9)-zz0(j9-1) if( dabs(dz) .lt. 0.0001_8 ) goto 510 !zz0(j9-1)とzz0(j9)が近い場合、何もしない dz= ( cutline-zz0(j9-1) ) / dz xx0(j9-1)= xx0(j9-1) + ( xx0(j9)-xx0(j9-1) ) * dz yy0(j9-1)= yy0(j9-1) + ( yy0(j9)-yy0(j9-1) ) * dz zz0(j9-1)= 0.0_8+cutline dz= zz0(j5)-zz0(j5-1) if( dabs(dz) .lt. 0.0001_8 ) goto 510 !zz0(j5-1)とzz0(j5)が近い場合、何もしない dz= ( cutline-zz0(j5-1) ) / dz xx0(j5)= xx0(j5-1) + ( xx0(j5)-xx0(j5-1) ) * dz yy0(j5)= yy0(j5-1) + ( yy0(j5)-yy0(j5-1) ) * dz zz0(j5)= 0.0_8+cutline zz0(j9-1:j5) = (screen+eyeoffset)/(zz0(j9-1:j5)+eyeoffset) n= j5 - (j9-1) + 1 polydata(0:n-1).wx = xx0(j9-1:j5)*zz0(j9-1:j5)*zoom polydata(0:n-1).wy = yy0(j9-1:j5)*zz0(j9-1:j5)*zoom goto 430 end if end do !4点すべてカットラインより前にあった zz0(0:3) = (screen+eyeoffset)/(zz0(0:3)+eyeoffset) polydata(0:3).wx = (xx0(0:3) + rotray(0)*t(0:3))*zz0(0:3)*zoom polydata(0:3).wy = (yy0(0:3) + rotray(1)*t(0:3))*zz0(0:3)*zoom n=4 430 continue if( isrgnsetted ) then call drawpolygon2( n ) if( afterpolydots .ge. 3 ) shadowcount=shadowcount+1 !3角形以上のとき、採用された end if end if 510 continue end do 500 continue end if end do !影の原因になる可能性のあるすべての立方体を調べた 400 continue end if !画像をキャプチャーする j2=beforeptrcapture do while (j2 .lt. ptrcapture) rgnxm=capture(j2+0) rgnym=capture(j2+1) dx=capture(j2+2) dy=capture(j2+3) j2=j2+4 c=dx*dy do j3=rgnym, rgnym+dy-1 !ポリゴンをビットマスク処理したものをキャプチャーする capture(c+j2:c+j2+dx-1)= ( vram2(rgnxm:rgnxm+dx-1,j3) .and. .not. capture(j2:j2+dx-1) ) j2=j2+dx end do j2=j2+c end do ! 1グループの処理終わり end do !ソートされた順に実際に表示する do j1=0, ppsort-1 j2=groupforserial(sortc(j1)) if( j2 .ne. -1 ) then rgnxm=capture(j2+0) rgnym=capture(j2+1) dx=capture(j2+2) dy=capture(j2+3) j2=j2+4 c=dx*dy do j3=rgnym, rgnym+dy-1 vram(rgnxm:rgnxm+dx-1,j3)= ( ( vram(rgnxm:rgnxm+dx-1,j3) .and. capture(j2:j2+dx-1) ) .or. capture(c+j2:c+j2+dx-1) ) j2=j2+dx end do end if end do end if end if 999 continue if(debugmode .and. shadowmode) then capturepercent=int2(ptrcapture*100 / maxcapture) cutanglespercent=int2(endofcutangles*100 / maxcutangles) end if end subroutine displaycube integer(2) function cmp_function_polygon(a1, a2) use common_variables implicit none integer(2) a1, a2 real(8) b1, b2 b1=distance(a1) b2=distance(a2) if( b1 .gt. b2 ) then cmp_function_polygon=int2(-1) return end if if( b1 .lt. b2 ) then cmp_function_polygon=int2(1) return end if cmp_function_polygon=int2(0) return end function cmp_function_polygon !平面(sur_x0, sur_y0, sur_z0)-(sur_x1, sur_y1, sur_z1)-(sur_x2, sur_y2, sur_z2)の式 ! a*x + b*y + c*z + d == 0を求める !結果は、sur_a, sur_b, sur_c, sur_d に入る subroutine getabcd() use common_variables implicit none real(8) a(0:2, 0:5) real(8) tmp, m, b integer(2) j, k, l, kp a(0,0)=sur_x0 a(0,1)=sur_x1 a(0,2)=sur_x2 a(1,0)=sur_y0 a(1,1)=sur_y1 a(1,2)=sur_y2 a(2,0)=sur_z0 a(2,1)=sur_z1 a(2,2)=sur_z2 do j=0, 2 do k=0, 2 if(j .eq. k) then a(j,3+k)=-1.0_8 else a(j,3+k)=0.0_8 end if end do end do do j=0, 2 do k=0, 1 a(j,k)=a(j,k)-a(j,2) end do end do do j=0, 1 m=dabs(a(j,j)) kp=j do k=j+1, 2 if( dabs(a(k,j)) .gt. m ) then m=dabs(a(k,j)) kp=k end if end do if(m .eq. 0) then result=messageboxqq('getabcdエラーです(最大ピボットが0)'C, 'Neo cubes'C, MB$OK) goto 240 end if if(kp .ne. j) then do k=j, 5 tmp=a(j,k) a(j,k)=a(kp,k) a(kp,k)=tmp end do end if do k=j+1, 2 b=a(k,j)/a(j,j) do l=j+1, 5 a(k,l)=a(k,l)-b*a(j,l) end do end do 240 continue end do sur_a=a(2,3) sur_b=a(2,4) sur_c=a(2,5) sur_d=a(2,2) !デバッグ******* b=dabs( sur_a*sur_x0 + sur_b*sur_y0 + sur_c*sur_z0 + sur_d ) b=b+dabs( sur_a*sur_x1 + sur_b*sur_y1 + sur_c*sur_z1 + sur_d ) b=b+dabs( sur_a*sur_x2 + sur_b*sur_y2 + sur_c*sur_z2 + sur_d ) if( b .gt. 0.0001_8 ) then result=messageboxqq('getabcdエラーです(式が0にならない)'C, 'Neo cubes'C, MB$OK) end if end subroutine getabcd subroutine drawpolygon2(d) use common_variables implicit none integer(2) d integer(2) x0, y0, x1, y1 integer(2) j4, j5 integer(2) pxx, pyy plx(0:d-1)=polydata(0:d-1).wx ply(0:d-1)=polydata(0:d-1).wy spcbuf=0 dots=d call poly2() afterpolydots=spcbuf if(spcbuf .lt. 3) return !3角形以下では何もしない !点を整数化し、重複する点を除外する !すべての点を含む矩形の範囲を知る j4=0 x0=size_x/2 + int2(cxbuf(ptrcbuf(spcbuf-1))) rgnxm2=x0 rgnxp2=x0 y0=size_y/2 + int2(cybuf(ptrcbuf(spcbuf-1))) rgnym2=y0 rgnyp2=y0 do j5=0, spcbuf-1 x1=size_x/2 + int2(cxbuf(ptrcbuf(j5))) if( x1 .lt. rgnxm2 ) rgnxm2=x1 if( x1 .gt. rgnxp2 ) rgnxp2=x1 y1=size_y/2 + int2(cybuf(ptrcbuf(j5))) if( y1 .lt. rgnym2 ) rgnym2=y1 if( y1 .gt. rgnyp2 ) rgnyp2=y1 if( (x1 .ne. x0) .or. (y1 .ne. y0) ) then dispdata(j4).xcoord=x1 dispdata(j4).ycoord=y1 j4=j4+1 x0=x1 y0=y1 end if end do afterpolydots=j4 if(j4 .lt. 3) return !3角形以下の場合は何もしない !リージョンが明らかに重ならないときは、何もしない if( rgnxpgroup .lt. rgnxm2 ) goto 999 if( rgnypgroup .lt. rgnym2 ) goto 999 if( rgnxp2 .lt. rgnxmgroup ) goto 999 if( rgnyp2 .lt. rgnymgroup ) goto 999 pxx=dispdata(0).xcoord pyy=dispdata(0).ycoord do j5=1, afterpolydots-2 trix(0)=pxx triy(0)=pyy trix(1)=dispdata(j5).xcoord triy(1)=dispdata(j5).ycoord trix(2)=dispdata(j5+1).xcoord triy(2)=dispdata(j5+1).ycoord call drawtriangle2() end do return 999 continue afterpolydots=0 end subroutine drawpolygon2 subroutine drawtriangle2() use common_variables implicit none integer(4) co integer(2) tmp real(4) dxybig, dxysmall real(4) xbig, xsmall integer(2) left, right integer(2) j integer(2) dybig, dysmall real(4) d !y座標が小さい順に並べる if(triy(0) .gt. triy(1)) then tmp=triy(0) triy(0)=triy(1) triy(1)=tmp tmp=trix(0) trix(0)=trix(1) trix(1)=tmp end if if(triy(0) .gt. triy(2)) then tmp=triy(0) triy(0)=triy(2) triy(2)=tmp tmp=trix(0) trix(0)=trix(2) trix(2)=tmp end if if(triy(1) .gt. triy(2)) then tmp=triy(2) triy(2)=triy(1) triy(1)=tmp tmp=trix(2) trix(2)=trix(1) trix(1)=tmp end if dybig=triy(2)-triy(0) dxybig=(trix(2)-trix(0))/(dybig*2.0_4) !上半分 dysmall=triy(1)-triy(0) dxysmall=(trix(1)-trix(0))/(dysmall*2.0_4) select case (dysmall) case(0) !横一線 left=imin0( trix(0), trix(1) ) right=imax0( trix(0), trix(1) ) vram2(left:right, triy(0))= ( vram2(left:right, triy(0)) .and. shadowcolor ) !塗る case default !一般 xbig=trix(0)+dxybig xsmall=trix(0)+dxysmall !最初の横一線 left=int2( 0.5_4+ amin1( trix(0)+0.0_4, xbig, xsmall ) ) right=int2( 0.5_4+ amax1( trix(0)+0.0_4, xbig, xsmall ) ) vram2(left:right, triy(0))= ( vram2(left:right, triy(0)) .and. shadowcolor ) !塗る !中の線 if(dysmall .ge. 2) then do j=triy(0)+1, triy(1)-1 left=int2( 0.5_4+ amin1( xbig, xsmall, xbig+dxybig*2, xsmall+dxysmall*2 ) ) right=int2( 0.5_4+ amax1( xbig, xsmall, xbig+dxybig*2, xsmall+dxysmall*2 ) ) vram2(left:right, j)= ( vram2(left:right, j) .and. shadowcolor ) !塗る xbig=xbig+dxybig*2 xsmall=xsmall+dxysmall*2 end do end if !最後の横一線 if(dybig .eq. dysmall) then d=dxybig else d=dxybig*2 end if left=int2( 0.5_4+ amin1( xbig, xsmall, xbig+d, xsmall+dxysmall ) ) right=int2( 0.5_4+ amax1( xbig, xsmall, xbig+d, xsmall+dxysmall ) ) vram2(left:right, triy(1))= ( vram2(left:right, triy(1)) .and. shadowcolor ) !塗る end select !下半分 dysmall=triy(2)-triy(1) dxysmall=(trix(2)-trix(1))/(dysmall*2.0_4) select case (dysmall) case(0) !横一線 left=imin0( trix(1), trix(2) ) right=imax0( trix(1), trix(2) ) vram2(left:right, triy(1))= ( vram2(left:right, triy(1)) .and. shadowcolor ) !塗る case default !一般 xbig=trix(2)-dxybig xsmall=trix(2)-dxysmall !最初の横一線 left=int2( 0.5_4+ amin1( trix(2)+0.0_4, xbig, xsmall ) ) right=int2( 0.5_4+ amax1( trix(2)+0.0_4, xbig, xsmall ) ) vram2(left:right, triy(2))= ( vram2(left:right, triy(2)) .and. shadowcolor ) !塗る !中の線 if(dysmall .ge. 2) then do j=triy(2)-1, triy(1)+1, -1 left=int2( 0.5_4+ amin1( xbig, xsmall, xbig-dxybig*2, xsmall-dxysmall*2 ) ) right=int2( 0.5_4+ amax1( xbig, xsmall, xbig-dxybig*2, xsmall-dxysmall*2 ) ) vram2(left:right, j)= ( vram2(left:right, j) .and. shadowcolor ) !塗る xbig=xbig-dxybig*2 xsmall=xsmall-dxysmall*2 end do end if !最後の横一線 if(dybig .eq. dysmall) then d=dxybig else d=dxybig*2 end if left=int2( 0.5_4+ amin1( xbig, xsmall, xbig-d, xsmall-dxysmall ) ) right=int2( 0.5_4+ amax1( xbig, xsmall, xbig-d, xsmall-dxysmall ) ) vram2(left:right, triy(1))= ( vram2(left:right, triy(1)) .and. shadowcolor ) !塗る end select end subroutine drawtriangle2 !(polydata(0).wx,polydata(0).wy) - (polydata(1).wx,polydata(1).wy) - ... - ! (polydata(d-1).wx,polydata(d-1).wy) を色 co で vram にポリゴンを表示する !afterpolydots=実際に描画された多角形の頂点数 subroutine drawpolygon(co, d) use common_variables implicit none integer(4) co integer(2) d integer(2) x0, y0, x1, y1 integer(2) j4, j5 integer(2) pxx, pyy plx(0:d-1)=polydata(0:d-1).wx ply(0:d-1)=polydata(0:d-1).wy spcbuf=0 dots=d call poly() afterpolydots=spcbuf if(spcbuf .lt. 3) goto 999 !3角形以下では何もしない !点を整数化し、重複する点を除外する !すべての点を含む矩形の範囲を知る j4=0 x0=size_x/2 + int2(cxbuf(ptrcbuf(spcbuf-1))) rgnxm=x0 rgnxp=x0 y0=size_y/2 + int2(cybuf(ptrcbuf(spcbuf-1))) rgnym=y0 rgnyp=y0 do j5=0, spcbuf-1 x1=size_x/2 + int2(cxbuf(ptrcbuf(j5))) if( x1 .lt. rgnxm ) rgnxm=x1 if( x1 .gt. rgnxp ) rgnxp=x1 y1=size_y/2 + int2(cybuf(ptrcbuf(j5))) if( y1 .lt. rgnym ) rgnym=y1 if( y1 .gt. rgnyp ) rgnyp=y1 if( (x1 .ne. x0) .or. (y1 .ne. y0) ) then dispdata(j4).xcoord=x1 dispdata(j4).ycoord=y1 j4=j4+1 x0=x1 y0=y1 end if end do afterpolydots=j4 if(j4 .lt. 3) goto 999 !3角形以下の場合は何もしない !グループ全体のリージョンを設定する if( .not. isrgnsetted ) then isrgnsetted=.true. !リージョンが1回以上セットされた rgnxmgroup=rgnxm rgnxpgroup=rgnxp rgnymgroup=rgnym rgnypgroup=rgnyp else if( rgnxm .lt. rgnxmgroup ) rgnxmgroup=rgnxm if( rgnxp .gt. rgnxpgroup ) rgnxpgroup=rgnxp if( rgnym .lt. rgnymgroup ) rgnymgroup=rgnym if( rgnyp .gt. rgnypgroup ) rgnypgroup=rgnyp end if vram3(rgnxm:rgnxp, rgnym:rgnyp)=16#ffffff pxx=dispdata(0).xcoord pyy=dispdata(0).ycoord do j5=1, afterpolydots-2 trix(0)=pxx triy(0)=pyy trix(1)=dispdata(j5).xcoord triy(1)=dispdata(j5).ycoord trix(2)=dispdata(j5+1).xcoord triy(2)=dispdata(j5+1).ycoord call drawtriangle(co) end do 999 continue end subroutine drawpolygon !整数座標( trix(0), triy(0) ) - ( trix(1), triy(1) ) - ( trix(2), triy(2) ) !の3角形を色 co で vram に表示する subroutine drawtriangle(co) use common_variables implicit none integer(4) co integer(2) tmp real(4) dxybig, dxysmall real(4) xbig, xsmall integer(2) left, right integer(2) j integer(2) dybig, dysmall real(4) d !y座標が小さい順に並べる if(triy(0) .gt. triy(1)) then tmp=triy(0) triy(0)=triy(1) triy(1)=tmp tmp=trix(0) trix(0)=trix(1) trix(1)=tmp end if if(triy(0) .gt. triy(2)) then tmp=triy(0) triy(0)=triy(2) triy(2)=tmp tmp=trix(0) trix(0)=trix(2) trix(2)=tmp end if if(triy(1) .gt. triy(2)) then tmp=triy(2) triy(2)=triy(1) triy(1)=tmp tmp=trix(2) trix(2)=trix(1) trix(1)=tmp end if dybig=triy(2)-triy(0) dxybig=(trix(2)-trix(0))/(dybig*2.0_4) !上半分 dysmall=triy(1)-triy(0) dxysmall=(trix(1)-trix(0))/(dysmall*2.0_4) select case (dysmall) case(0) !横一線 left=imin0( trix(0), trix(1) ) right=imax0( trix(0), trix(1) ) vram2(left:right, triy(0))= co !塗る vram3(left:right, triy(0))= 0 !塗る case default !一般 xbig=trix(0)+dxybig xsmall=trix(0)+dxysmall !最初の横一線 left=int2( 0.5_4+ amin1( trix(0)+0.0_4, xbig, xsmall ) ) right=int2( 0.5_4+ amax1( trix(0)+0.0_4, xbig, xsmall ) ) vram2(left:right, triy(0))= co !塗る vram3(left:right, triy(0))= 0 !塗る !中の線 if(dysmall .ge. 2) then do j=triy(0)+1, triy(1)-1 left=int2( 0.5_4+ amin1( xbig, xsmall, xbig+dxybig*2, xsmall+dxysmall*2 ) ) right=int2( 0.5_4+ amax1( xbig, xsmall, xbig+dxybig*2, xsmall+dxysmall*2 ) ) vram2(left:right, j)= co !塗る vram3(left:right, j)= 0 !塗る xbig=xbig+dxybig*2 xsmall=xsmall+dxysmall*2 end do end if !最後の横一線 if(dybig .eq. dysmall) then d=dxybig else d=dxybig*2 end if left=int2( 0.5_4+ amin1( xbig, xsmall, xbig+d, xsmall+dxysmall ) ) right=int2( 0.5_4+ amax1( xbig, xsmall, xbig+d, xsmall+dxysmall ) ) vram2(left:right, triy(1))= co !塗る vram3(left:right, triy(1))= 0 !塗る end select !下半分 dysmall=triy(2)-triy(1) dxysmall=(trix(2)-trix(1))/(dysmall*2.0_4) select case (dysmall) case(0) !横一線 left=imin0( trix(1), trix(2) ) right=imax0( trix(1), trix(2) ) vram2(left:right, triy(1))= co !塗る vram3(left:right, triy(1))= 0 !塗る case default !一般 xbig=trix(2)-dxybig xsmall=trix(2)-dxysmall !最初の横一線 left=int2( 0.5_4+ amin1( trix(2)+0.0_4, xbig, xsmall ) ) right=int2( 0.5_4+ amax1( trix(2)+0.0_4, xbig, xsmall ) ) vram2(left:right, triy(2))= co !塗る vram3(left:right, triy(2))= 0 !塗る !中の線 if(dysmall .ge. 2) then do j=triy(2)-1, triy(1)+1, -1 left=int2( 0.5_4+ amin1( xbig, xsmall, xbig-dxybig*2, xsmall-dxysmall*2 ) ) right=int2( 0.5_4+ amax1( xbig, xsmall, xbig-dxybig*2, xsmall-dxysmall*2 ) ) vram2(left:right, j)= co !塗る vram3(left:right, j)= 0 !塗る xbig=xbig-dxybig*2 xsmall=xsmall-dxysmall*2 end do end if !最後の横一線 if(dybig .eq. dysmall) then d=dxybig else d=dxybig*2 end if left=int2( 0.5_4+ amin1( xbig, xsmall, xbig-d, xsmall-dxysmall ) ) right=int2( 0.5_4+ amax1( xbig, xsmall, xbig-d, xsmall-dxysmall ) ) vram2(left:right, triy(1))= co !塗る vram3(left:right, triy(1))= 0 !塗る end select end subroutine drawtriangle !(plx(0), ply(0)) - (ply(1), ply(1)) - ... - (plx(dots-1), ply(dots-1)) ! のポリゴンと四角リージョンの論理積をとる !cxbuf(spcbuf++), cybuf(spcbuf++) に atan2 でソートされた頂点が入る !ソートされた結果はポインタの配列 ptrcbuf(0:spcbuf-1) に入っている subroutine poly() use common_variables implicit none integer(2), external :: cmp_function_poly real(8) poly_a(0:dots-1), poly_b(0:dots-1), poly_c(0:dots-1) real(8) poly_sign(0:dots-1) real(8) cx, cy, sign integer(2) j, k !四角リージョンの内側にあるポリゴンの頂点は採用する k=0 do j=0, dots-1 if( plx(j) .ge. 0.0_8-size_x/2 ) then if( plx(j) .le. size_x/2-1.0_8 ) then if( ply(j) .ge. 0.0_8-size_y/2 ) then if( ply(j) .le. size_y/2-1.0_8 ) then cxbuf(spcbuf)=plx(j) cybuf(spcbuf)=ply(j) spcbuf=spcbuf+1 k=k+1 end if end if end if end if end do if(k .eq. dots) goto 100 !すべての点が四角リージョンの内側にある場合、すぐにソート処理へ行く cx=0.0_8 cy=0.0_8 do j=0, dots-1 cx=cx+plx(j) cy=cy+ply(j) end do cx=cx/dots cy=cy/dots do j=0, dots-2 line_x0=plx(j) line_y0=ply(j) line_x1=plx(j+1) line_y1=ply(j+1) call getabc() poly_a(j)=line_a poly_b(j)=line_b poly_c(j)=line_c end do line_x0=plx(dots-1) line_y0=ply(dots-1) line_x1=plx(0) line_y1=ply(0) call getabc() poly_a(dots-1)=line_a poly_b(dots-1)=line_b poly_c(dots-1)=line_c poly_sign(0:dots-1)= poly_a(0:dots-1)*cx + poly_b(0:dots-1)*cy + poly_c(0:dots-1) !ポリゴンの内側にある四角リージョンの頂点は採用する do j=0, 3 do k=0, dots-1 sign= poly_a(k)*rctx(j) + poly_b(k)*rcty(j) + poly_c(k) if( poly_sign(k)*sign .lt. 0.0_8 ) goto 200 !異符号は採用しない end do cxbuf(spcbuf)=rctx(j) cybuf(spcbuf)=rcty(j) spcbuf=spcbuf+1 200 continue end do !ポリゴンの線と四角リージョンの線の交点が有効なものは採用する do j=0, dots-2 crx(0)=plx(j) cry(0)=ply(j) crx(1)=plx(j+1) cry(1)=ply(j+1) do k=0, 2 crx(2)=rctx(k) cry(2)=rcty(k) crx(3)=rctx(k+1) cry(3)=rcty(k+1) call cross() end do crx(2)=rctx(3) cry(2)=rcty(3) crx(3)=rctx(0) cry(3)=rcty(0) call cross() end do crx(0)=plx(dots-1) cry(0)=ply(dots-1) crx(1)=plx(0) cry(1)=ply(0) do k=0, 2 crx(2)=rctx(k) cry(2)=rcty(k) crx(3)=rctx(k+1) cry(3)=rcty(k+1) call cross() end do crx(2)=rctx(3) cry(2)=rcty(3) crx(3)=rctx(0) cry(3)=rcty(0) call cross() 100 continue !ソートする if(spcbuf .gt. 0) then do j=0, spcbuf-1 ptrcbuf(j)=j end do end if if(spcbuf .gt. 3) then cx=0.0_8 cy=0.0_8 do j=0, spcbuf-1 cx=cx+cxbuf(j) cy=cy+cybuf(j) end do cx=cx/spcbuf cy=cy/spcbuf do j=0, spcbuf-1 degree_cbuf(j)= datan2( cybuf(j)-cy, cxbuf(j)-cx ) end do CALL qsort(ptrcbuf, spcbuf, 2, cmp_function_poly) end if end subroutine poly integer(2) function cmp_function_poly(a1, a2) use common_variables implicit none integer(2) a1, a2 real(8) b1, b2 b1=degree_cbuf(a1) b2=degree_cbuf(a2) if( b1 .gt. b2 ) then cmp_function_poly=int2(-1) return end if if( b1 .lt. b2 ) then cmp_function_poly=int2(1) return end if cmp_function_poly=int2(0) return end function cmp_function_poly subroutine poly2() use common_variables implicit none integer(2), external :: cmp_function_poly real(8) poly_a(0:dots-1), poly_b(0:dots-1), poly_c(0:dots-1) real(8) poly_sign(0:dots-1) real(8) cx, cy, sign integer(2) j, k real(8) rgnxmr, rgnxpr, rgnymr, rgnypr, x, y !四角リージョンの内側にあるポリゴンの頂点は採用する rgnxmr=plx(0) rgnxpr=rgnxmr rgnymr=ply(0) rgnypr=rgnymr k=0 do j=0, dots-1 x=plx(j) if( x .lt. rgnxmr ) rgnxmr=x if( x .gt. rgnxpr ) rgnxpr=x y=ply(j) if( y .lt. rgnymr ) rgnymr=y if( y .gt. rgnypr ) rgnypr=y if( x .ge. 0.0_8-size_x/2 ) then if( x .le. size_x/2-1.0_8 ) then if( y .ge. 0.0_8-size_y/2 ) then if( y .le. size_y/2-1.0_8 ) then cxbuf(spcbuf)=x cybuf(spcbuf)=y spcbuf=spcbuf+1 k=k+1 end if end if end if end if end do !リージョンが明らかに重ならないときは、何もしない if( 0.0_8+rgnxpgroup .lt. size_x/2+rgnxmr ) goto 999 if( 0.0_8+rgnypgroup .lt. size_y/2+rgnymr ) goto 999 if( size_x/2+rgnxpr .lt. 0.0_8+rgnxmgroup ) goto 999 if( size_y/2+rgnypr .lt. 0.0_8+rgnymgroup ) goto 999 if(k .eq. dots) goto 100 !すべての点が四角リージョンの内側にある場合、すぐにソート処理へ行く cx=0.0_8 cy=0.0_8 do j=0, dots-1 cx=cx+plx(j) cy=cy+ply(j) end do cx=cx/dots cy=cy/dots do j=0, dots-2 line_x0=plx(j) line_y0=ply(j) line_x1=plx(j+1) line_y1=ply(j+1) call getabc() poly_a(j)=line_a poly_b(j)=line_b poly_c(j)=line_c end do line_x0=plx(dots-1) line_y0=ply(dots-1) line_x1=plx(0) line_y1=ply(0) call getabc() poly_a(dots-1)=line_a poly_b(dots-1)=line_b poly_c(dots-1)=line_c poly_sign(0:dots-1)= poly_a(0:dots-1)*cx + poly_b(0:dots-1)*cy + poly_c(0:dots-1) !ポリゴンの内側にある四角リージョンの頂点は採用する do j=0, 3 do k=0, dots-1 sign= poly_a(k)*rctx(j) + poly_b(k)*rcty(j) + poly_c(k) if( poly_sign(k)*sign .lt. 0.0_8 ) goto 200 !異符号は採用しない end do cxbuf(spcbuf)=rctx(j) cybuf(spcbuf)=rcty(j) spcbuf=spcbuf+1 200 continue end do !ポリゴンの線と四角リージョンの線の交点が有効なものは採用する do j=0, dots-2 crx(0)=plx(j) cry(0)=ply(j) crx(1)=plx(j+1) cry(1)=ply(j+1) do k=0, 2 crx(2)=rctx(k) cry(2)=rcty(k) crx(3)=rctx(k+1) cry(3)=rcty(k+1) call cross() end do crx(2)=rctx(3) cry(2)=rcty(3) crx(3)=rctx(0) cry(3)=rcty(0) call cross() end do crx(0)=plx(dots-1) cry(0)=ply(dots-1) crx(1)=plx(0) cry(1)=ply(0) do k=0, 2 crx(2)=rctx(k) cry(2)=rcty(k) crx(3)=rctx(k+1) cry(3)=rcty(k+1) call cross() end do crx(2)=rctx(3) cry(2)=rcty(3) crx(3)=rctx(0) cry(3)=rcty(0) call cross() 100 continue !ソートする if(spcbuf .gt. 0) then do j=0, spcbuf-1 ptrcbuf(j)=j end do end if if(spcbuf .gt. 3) then cx=0.0_8 cy=0.0_8 do j=0, spcbuf-1 cx=cx+cxbuf(j) cy=cy+cybuf(j) end do cx=cx/spcbuf cy=cy/spcbuf do j=0, spcbuf-1 degree_cbuf(j)= datan2( cybuf(j)-cy, cxbuf(j)-cx ) end do CALL qsort(ptrcbuf, spcbuf, 2, cmp_function_poly) end if return 999 continue spcbuf=0 end subroutine poly2 !(0, 0) - (size_x-1, size_y-1) の四角リージョンを設定する(自作シェーダー表示用) !最初に1度だけ呼ばれる !rctrgn_a(0~3), rctrgn_b(0~3), rctrgn_c(0~3) に各直線のa,b,cが入る !rctrgn_sign(0~3) にポリゴンの真ん中の点に対する符号が入る subroutine setrctrgn() use common_variables implicit none real(8) cx, cy integer(2) j rctx(0)=0.0_8-size_x/2 rcty(0)=0.0_8-size_y/2 rctx(1)=0.0_8+size_x/2-1 rcty(1)=0.0_8-size_y/2 rctx(2)=0.0_8+size_x/2-1 rcty(2)=0.0_8+size_y/2-1 rctx(3)=0.0_8-size_x/2 rcty(3)=0.0_8+size_y/2-1 cx=0.0_8 cy=0.0_8 do j=0, 3 cx=cx+rctx(j) cy=cy+rcty(j) end do cx=cx/4 cy=cy/4 do j=0, 2 line_x0=rctx(j) line_y0=rcty(j) line_x1=rctx(j+1) line_y1=rcty(j+1) call getabc() rctrgn_a(j)=line_a rctrgn_b(j)=line_b rctrgn_c(j)=line_c end do line_x0=rctx(3) line_y0=rcty(3) line_x1=rctx(0) line_y1=rcty(0) call getabc() rctrgn_a(3)=line_a rctrgn_b(3)=line_b rctrgn_c(3)=line_c rctrgn_sign(0:3)= rctrgn_a(0:3)*cx + rctrgn_b(0:3)*cy + rctrgn_c(0:3) end subroutine setrctrgn !直線(line_x0, line_y0)-(line_x1, line_y1)の式 a*x + b*y + c == 0を求める !結果は、line_a, line_b, line_c に入る subroutine getabc() use common_variables implicit none !dabs(x1-x0) と dabs(y1-y0) のスパンの大きいほうを選ぶ ! !y1-y0が大きいとき、次の方程式を解く !(x0 + b*y0 + c == 0) && (x1 + b*y1 + c == 0) !a=1, b=(x0 - x1)/(y1-y0), c=(x1 y0 - x0 y1)/(y1-y0) ! !x1-x0が大きいとき、次の方程式を解く !(a*x0 + y0 + c == 0) && (a*x1 + y1 + c == 0) !a=(y0 - y1)/(x1-x0), b=1, c=(x0 y1 -x1 y0)/(x1-x0) real(8) x1mx0, y1my0 real(8) x1y0mx0y1 x1mx0=line_x1-line_x0 y1my0=line_y1-line_y0 x1y0mx0y1=line_x1*line_y0-line_x0*line_y1 if( dabs(x1mx0) .gt. dabs(y1my0) ) then !x1-x0が大きいとき if(x1mx0 .eq. 0.0_8) then !点になっている line_a=1.0_8 line_b=0.0_8 line_c=-line_x0 else !a=(y0 - y1)/(x1-x0), b=1, c=(x0 y1 -x1 y0)/(x1-x0) line_a=-y1my0/x1mx0 line_b=1.0_8 line_c=-x1y0mx0y1/x1mx0 end if else !y1-y0が大きいとき if(y1my0 .eq. 0.0_8) then !点になっている line_a=0.0_8 line_b=1.0_8 line_c=-line_y0 else !a=1, b=(x0 - x1)/(y1-y0), c=(x1 y0 - x0 y1)/(y1-y0) line_a=1.0_8 line_b=-x1mx0/y1my0 line_c=x1y0mx0y1/y1my0 endif end if end subroutine getabc !直線(crx(0), cry(0))-(crx(1), cry(1)) と (crx(2), cry(2))-(crx(3), cry(3))の交点を計算する !結果は、cxbuf(spcbuf++), cybuf(spcbuf++)に入る subroutine cross() use common_variables implicit none !次の連立方程式を s 及び t について解く ! !x=x0+( x1-x0 )*s !y=y0+( y1-y0 )*s ! !x=x2+( x3-x2 )*t !y=y2+( y3-y2 )*t ! !s=x3 (y0 - y2) + x0 (y2 - y3) + x2 (-y0 + y3) / ! -(x2 - x3) (y0 - y1) + (x0 - x1) (y2 - y3) ! !t=x2 (y0 - y1) + x0 (y1 - y2) + x1 (-y0 + y2) / ! (x2 - x3) (y0 - y1) - (x0 - x1) (y2 - y3) ! !0<=s<=1 .and. 0<=t<=1 ならば交点が存在する real(8) x0,y0, x1,y1, x2,y2, x3,y3 real(8) s, t, u, us, ut real(8) y0y1, y0y2, y2y3 real(8) tmp, abs01, abs23, xm, ym, xp, yp logical(4) reverse x0=crx(0) y0=cry(0) x1=crx(1) y1=cry(1) x2=crx(2) y2=cry(2) x3=crx(3) y3=cry(3) y0y1=y0-y1 y0y2=y0-y2 y2y3=y2-y3 u= (x2 - x3) * y0y1 - (x0 - x1) * y2y3 us= x3 * y0y2 + x0 * y2y3 + x2 * (y3 - y0) ut= x2 * y0y1 + x0 * (y1 - y2) - x1 * y0y2 if( u .ne. 0.0_8 ) then s= us / -u t= ut / u if( s .ge. 0.0_8 ) then if( s .le. 1.0_8 ) then if( t .ge. 0.0_8 ) then if( t .le. 1.0_8 ) then cxbuf(spcbuf)=x0+(x1-x0)*s cybuf(spcbuf)=y0+(y1-y0)*s spcbuf=spcbuf+1 end if end if end if end if else !u==0のとき if( (us .eq. 0.0_8) .and. (ut .eq. 0.0_8) ) then !2つの線が1直線上に重なっている場合を救済する abs01=(x1-x0)**2+(y1-y0)**2 abs23=(x3-x2)**2+(y3-y2)**2 !スパンの長い方をx0,y0,x1,y1とする if( abs01 .lt. abs23 ) then abs01=abs23 tmp=x0 x0=x2 x2=tmp tmp=y0 y0=y2 y2=tmp tmp=x1 x1=x3 x3=tmp tmp=y1 y1=y3 y3=tmp end if if( abs01 .eq. 0.0_8 ) then !点になっている if( (x0 .eq. x2) .and. (y0 .eq. y2) ) then cxbuf(spcbuf)=x0 cybuf(spcbuf)=y0 spcbuf=spcbuf+1 end if else !スパンの長い方をxとする if( dabs(x1-x0) .lt. dabs(y1-y0) ) then tmp=x0 x0=y0 y0=tmp tmp=x1 x1=y1 y1=tmp tmp=x2 x2=y2 y2=tmp tmp=x3 x3=y3 y3=tmp reverse=.true. else reverse=.false. end if !直線で比較する if( x0 .gt. x1 ) then tmp=x0 x0=x1 x1=tmp tmp=y0 y0=y1 y1=tmp end if if( x2 .gt. x3 ) then tmp=x2 x2=x3 x3=tmp tmp=y2 y2=y3 y3=tmp end if !マイナス方向をカット if( x0 .lt. x2 ) then xm=x2 ym=y2 else xm=x0 ym=y0 end if !プラス方向をカット if( x1 .gt. x3 ) then xp=x3 yp=y3 else xp=x1 yp=y1 end if !---> xm,ym ---> xp,yp ---> の場合、救済可能 if( xm .le. xp ) then !(xm,ym)および(xp,yp)を登録 if(reverse) then tmp=xm xm=ym ym=tmp tmp=xp xp=yp yp=tmp end if cxbuf(spcbuf)=xm cybuf(spcbuf)=ym spcbuf=spcbuf+1 cxbuf(spcbuf)=xp cybuf(spcbuf)=yp spcbuf=spcbuf+1 end if end if end if end if end subroutine cross !ファイルをロードする subroutine loadfile() use common_variables USE IFPORT implicit none CHARACTER(256) pathname INTEGER(4) pathlen integer(4) io integer(4) j result = SETACTIVEQQ (childwindow1) CALL SETTEXTPOSITION (INT2(1), INT2(1), curpos) write(childwindow1,*) '*** ロード ***' write(childwindow1,*) 'ファイルをロードします' write(childwindow1,*) '1〜9, a〜z のばんごうを押してください(0=やめる)' call revewfile() 100 continue call selectfilenumber() if(filenumber .eq. -1) goto 100 if(filenumber .ne. 0) then pathlen = FINDFILEQQ(filenamelist(filenumber), "", pathname) if (pathlen .eq. 0) then result=messageboxqq('ファイルがありません'C, 'Neo cubes'C, MB$OK) goto 999 end if open(fileequipnumber, file=filenamelist(filenumber), iostat=io) if (io .ne. 0) then result=messageboxqq('オープンできません'C, 'Neo cubes'C, MB$OK) goto 999 end if !読み込む read(fileequipnumber, *, end=888) ptrcube !立方体の位置データ数 read(fileequipnumber, *, end=888) eye(0), eye(1), eye(2) !現在位置 read(fileequipnumber, *, end=888) matrix0(0,0) !視点方向 read(fileequipnumber, *, end=888) matrix0(1,0) !視点方向 read(fileequipnumber, *, end=888) matrix0(2,0) !視点方向 read(fileequipnumber, *, end=888) matrix0(0,1) !視点方向 read(fileequipnumber, *, end=888) matrix0(1,1) !視点方向 read(fileequipnumber, *, end=888) matrix0(2,1) !視点方向 read(fileequipnumber, *, end=888) matrix0(0,2) !視点方向 read(fileequipnumber, *, end=888) matrix0(1,2) !視点方向 read(fileequipnumber, *, end=888) matrix0(2,2) !視点方向 read(fileequipnumber, *, end=888) ray(0) !光源方向 read(fileequipnumber, *, end=888) ray(1) !光源方向 read(fileequipnumber, *, end=888) ray(2) !光源方向 read(fileequipnumber, *, end=888) shadowmode !影モード if(ptrcube .gt. 0) then do j=0, ptrcube-1 !cube(xyz, 通し番号) read(fileequipnumber, *, end=888) cube(0,j), cube(1,j), cube(2,j) end do end if 888 continue close(fileequipnumber, iostat=io) if (io .ne. 0) then result=messageboxqq('クローズできません'C, 'Neo cubes'C, MB$OK) goto 999 end if result=messageboxqq('読み込みました'C, 'Neo cubes'C, MB$OK) 999 continue end if end subroutine loadfile !ファイルをセーブする subroutine savefile() use common_variables USE IFPORT implicit none integer(4) io CHARACTER(256) pathname INTEGER(4) pathlen integer(4) j result = SETACTIVEQQ (childwindow1) CALL SETTEXTPOSITION (INT2(1), INT2(1), curpos) write(childwindow1,*) '*** セーブ ***' write(childwindow1,*) 'ファイルをセーブします' write(childwindow1,*) '1〜9, a〜z のばんごうを押してください(0=やめる)' call revewfile() 100 continue call selectfilenumber() if(filenumber .eq. -1) goto 100 if(filenumber .ne. 0) then pathlen = FINDFILEQQ(filenamelist(filenumber), "", pathname) if (pathlen .ne. 0) then result=messageboxqq('ファイル上書きしますか?'C, 'Neo cubes'C, MB$OKCANCEL) if (result .eq. MB$IDCANCEL) goto 999 end if open(fileequipnumber, file=filenamelist(filenumber), iostat=io) if (io .ne. 0) then result=messageboxqq('オープンできません'C, 'Neo cubes'C, MB$OK) goto 999 end if !書き込む write(fileequipnumber, *, iostat=io) ptrcube !立方体の位置データ数 write(fileequipnumber, *, iostat=io) eye(0), eye(1), eye(2) !現在位置 write(fileequipnumber, *, iostat=io) matrix0(0,0) !視点方向 write(fileequipnumber, *, iostat=io) matrix0(1,0) !視点方向 write(fileequipnumber, *, iostat=io) matrix0(2,0) !視点方向 write(fileequipnumber, *, iostat=io) matrix0(0,1) !視点方向 write(fileequipnumber, *, iostat=io) matrix0(1,1) !視点方向 write(fileequipnumber, *, iostat=io) matrix0(2,1) !視点方向 write(fileequipnumber, *, iostat=io) matrix0(0,2) !視点方向 write(fileequipnumber, *, iostat=io) matrix0(1,2) !視点方向 write(fileequipnumber, *, iostat=io) matrix0(2,2) !視点方向 write(fileequipnumber, *, iostat=io) ray(0) !光源方向 write(fileequipnumber, *, iostat=io) ray(1) !光源方向 write(fileequipnumber, *, iostat=io) ray(2) !光源方向 write(fileequipnumber, *, iostat=io) shadowmode !影モード if(ptrcube .gt. 0) then do j=0, ptrcube-1 !cube(xyz, 通し番号) write(fileequipnumber, *, iostat=io) cube(0,j), cube(1,j), cube(2,j) end do end if close(fileequipnumber, iostat=io) if (io .ne. 0) then result=messageboxqq('クローズできません'C, 'Neo cubes'C, MB$OK) goto 999 end if result=messageboxqq('書き込みました'C, 'Neo cubes'C, MB$OK) 999 continue end if end subroutine savefile !ファイルの有無を表示する subroutine revewfile() use common_variables USE IFPORT implicit none CHARACTER(256) pathname INTEGER(4) pathlen integer(2) j character(1) i do j=1, 35 if( (j .ge. 1) .and. (j .le. 9) ) then i=char(48+j) end if if( (j .ge. 10) .and. (j .le. 35) ) then i=char(97+j-10) end if pathlen = FINDFILEQQ(filenamelist(j), "", pathname) if (pathlen .ne. 0) then write(childwindow1,*) 'ファイル番号', j, '(', i, '): 満' else write(childwindow1,*) 'ファイル番号', j, '(', i, '): 空' end if end do end subroutine revewfile !ファイル番号を入力する subroutine selectfilenumber() use common_variables implicit none filenumber=-1 key=incharqq() select case (key) case(ichar('1')) filenumber=1 case(ichar('2')) filenumber=2 case(ichar('3')) filenumber=3 case(ichar('4')) filenumber=4 case(ichar('5')) filenumber=5 case(ichar('6')) filenumber=6 case(ichar('7')) filenumber=7 case(ichar('8')) filenumber=8 case(ichar('9')) filenumber=9 case(ichar('0')) filenumber=0 end select if( (key .ge. ichar('a')) .and. (key .le. ichar('z')) ) then filenumber=key-ichar('a')+10 end if end subroutine selectfilenumber |