misc/hypotrochoid.s- Source code ソースコード - XEiJ - STUDIO KAMADA
misc/hypotrochoid.s

    ;========================================================================================
    ;  hypotrochoid.s
    ;  Copyright (C) 2003-2025 Makoto Kamada
    ;
    ;  This file is part of the XEiJ (X68000 Emulator in Java).
    ;  You can use, modify and redistribute the XEiJ if the conditions are met.
    ;  Read the XEiJ License for more details.
    ;  https://stdkmd.net/xeij/
    ;========================================================================================

    ;----------------------------------------------------------------
    ;  hypotrochoid.x
    ;	XEiJの疑似グラフィック画面(4096個のパターンを敷き詰めたバックグラウンド)にハイポトロコイドを描きます。
    ;	青(S)と紫(S)はスプライト画面(BG0とBG1)、赤(T)はテキスト画面、緑(G)はグラフィック画面です。
    ;	改造メニューの4096個のパターンチェックボックスと768x512でスプライトを表示チェックボックスと
    ;	512x512でBG1を表示チェックボックスをONにしてリセットしてから実行します。
    ;	BREAK/CTRL+C/ESCキーで終了、動作中はその他のキーで停止。停止中はENTERキーで再開、その他のキーでコマ送りします。
    ;	X68000実機では動きません。
    ;----------------------------------------------------------------

    ;----------------------------------------------------------------
    ;ハイポトロコイド
    ;	定円の内側に沿って動円が転がるとき、動円に固定された点の軌跡をハイポトロコイドと呼びます。
    ;	定円の中心を(0,0)、半径をR、動円の半径をr、動円の中心から点までの距離をdとします。
    ;	定円と動円の周の長さの比から、動円が左に1周する間に動円は接線に対して右にR/r回転します。
    ;	同時に接線が左に1回転するので、合わせて動円は右に(R-r)/r回転します。
    ;	動円の中心の方向をtとすると、点の位置は((R-r)*cos(t)+d*cos((R-r)/r*t),(R-r)*sin(t)-d*sin((R-r)/r*t))となります。
    ;	動円が左にn周する間に動円は右に(R-r)/r*n回転します。
    ;	R,rが整数のとき、点が最初の位置に戻るまでの周期n0は(R-r)/r*nが整数になる最小のn、すなわちn0=r/gcd(R-r,r)です。
    ;	https://en.wikipedia.org/wiki/Hypotrochoid
    ;----------------------------------------------------------------

    	.include	control2.mac
    	.include	crtc.equ
    	.include	doscall.mac
    	.include	fefunc.mac
    	.include	iocscall.mac
    	.include	mfp.equ
    	.include	misc.mac
    	.include	push2.mac
    	.include	sprc.equ
    	.include	vicon.equ

    ;引数
    	lea.l	1(a2),a0
    	do
    	;R 定円の半径
    		bsr	nextword
    		break	eq			;指定なし。既定値を使う
    		FPACK	__STOL
    		goto	cs,error		;整数がない。エラー終了
    		goto	<tst.l d0>,le,error	;1より小さい。エラー終了
    		goto	<cmp.l #1000000,d0>,gt,error	;1000000より大きい。エラー終了
    		move.l	d0,int_R
    	;r 動円の半径
    		bsr	nextword
    		break	eq			;指定なし。既定値を使う
    		FPACK	__STOL
    		goto	cs,error		;整数がない。エラー終了
    		goto	<tst.l d0>,le,error	;1より小さい。エラー終了
    		goto	<cmp.l #1000000,d0>,gt,error	;1000000より大きい。エラー終了
    		goto	<cmp.l int_R,d0>,ge,error	;rがRと等しいかより大きい。エラー終了
    		move.l	d0,int_r
    	;d 動円の中心から点までの距離
    		bsr	nextword
    		break	eq			;指定なし。既定値を使う
    		FPACK	__STOD
    		goto	cs,error		;数値がない。エラー終了
    		FPACK	__DTST
    		goto	lt,error		;0より小さい。エラー終了
    		move.l	d0,d2
    		move.l	d1,d3
    		move.l	#1000000,d0
    		FPACK	__LTOD
    		FPACK	__DCMP
    		goto	lt,error		;1000000より大きい。エラー終了
    		movem.l	d2-d3,dbl_d
    	;f 1周(≠1周期)の点の数
    		bsr	nextword
    		break	eq			;指定なし。既定値を使う
    		FPACK	__STOL
    		goto	cs,error		;数値がない。エラー終了
    		goto	<tst.l d0>,le,error	;1より小さい。エラー終了
    		goto	<cmp.l #1000000,d0>,gt,error	;1000000より大きい。エラー終了
    		move.l	d0,int_f
    	while	f

    ;引数で決まる値
    ;R 定円の半径
    	move.l	int_R,d0
    	FPACK	__LTOD
    	movem.l	d0-d1,dbl_R
    ;r 動円の半径
    	move.l	int_r,d0
    	FPACK	__LTOD
    	movem.l	d0-d1,dbl_r
    ;Rr=R-r 定円の中心から動円の中心までの距離
    	move.l	int_R,d0
    	sub.l	int_r,d0
    	move.l	d0,int_Rr
    	FPACK	__LTOD
    	movem.l	d0-d1,dbl_Rr
    ;Rrr=(R-r)/r 点の速度
    ;	movem.l	dbl_Rr,d0-d1
    	movem.l	dbl_r,d2-d3
    	FPACK	__DDIV
    	movem.l	d0-d1,dbl_Rrr
    ;n0=r/gcd(R-r,r) 周期
    	move.l	int_Rr,d0		;d0=前回の余り=R-r。0ではない
    	move.l	int_r,d1		;d1=前回の除数=r。0ではない
    	do
    					;d0=前回の余り,d1=前回の除数
    					;前回の除数→被除数,前回の余り→除数
    		exg.l	d0,d1		;d0=被除数,d1=除数
    		FPACK	__LMOD		;d0=余り,d1=除数
    	while	<tst.l d0>,ne		;余りが0になるまで繰り返す
    					;余りが0になったときの除数=gcd(R-r,r)
    	move.l	int_r,d0		;d0=r
    	FPACK	__LDIV			;d0=n0=r/gcd(R-r,r)
    	move.l	d0,int_n0
    ;fn0=f*n0 n0周(=1周期)の点の数
    	move.l	int_f,d0
    	move.l	int_n0,d1
    	FPACK	__LMUL
    	move.l	d0,int_fn0
    ;s=RR/(R-r+d) 倍率
    	movem.l	dbl_Rr,d0-d1
    	movem.l	dbl_d,d2-d3
    	FPACK	__DADD
    	move.l	d0,d2
    	move.l	d1,d3
    	movem.l	dbl_RR,d0-d1
    	FPACK	__DDIV
    	movem.l	d0-d1,dbl_s
    ;f 1周(≠1周期)の点の数
    	move.l	int_f,d0
    	FPACK	__LTOD
    	movem.l	d0-d1,dbl_f
    ;dt=2*pi/f 角度の増分
    	moveq.l	#2,d0
    	FPACK	__LTOD
    	FPACK	__NPI
    	movem.l	dbl_f,d2-d3
    	FPACK	__DDIV
    	movem.l	d0-d1,dbl_dt

    ;スクロールの軌道を作る
    ;	中心(128,256)半径(128,256)の円
    orbit_length	equ	(orbit_end-orbit)/4
    	move.l	#orbit_length,d0
    	FPACK	__LTOD
    	move.l	d0,d2			;d2d3=n
    	move.l	d1,d3
    	moveq.l	#2,d0
    	FPACK	__LTOD
    	FPACK	__NPI			;d0d1=2*pi
    	FPACK	__DDIV			;d0d1=2*pi/n=dt
    	movea.l	d0,a4			;a4a5=dt
    	movea.l	d1,a5
    	move.l	#128,d0
    	FPACK	__LTOD
    	movea.l	d0,a0			;a0a1=128
    	movea.l	d1,a1
    	move.l	#256,d0
    	FPACK	__LTOD
    	movea.l	d0,a2			;a2a3=256
    	movea.l	d1,a3
    	moveq.l	#0,d4			;d4d5=t
    	moveq.l	#0,d5
    	lea.l	orbit,a6
    	move.w	#orbit_length-1,d7
    	for	d7
    		move.l	d4,d0			;d0d1=t
    		move.l	d5,d1
    		FPACK	__COS			;d0d1=cos(t)
    		move.l	a0,d2			;d2d3=128
    		move.l	a1,d3
    		FPACK	__DMUL			;d0d1=128*cos(t)
    		exg.l	d0,d2			;d0d1=128
    		exg.l	d1,d3			;d2d3=128*cos(t)
    		FPACK	__DSUB			;d0d1=128-128*cos(t)
    		FPACK	__DTOL			;d0=128-128*cos(t)
    		move.w	d0,(a6)+		;x
    	;
    		move.l	d4,d0			;d0d1=t
    		move.l	d5,d1
    		FPACK	__SIN			;d0d1=sin(t)
    		move.l	a2,d2			;d2d3=256
    		move.l	a3,d3
    		FPACK	__DMUL			;d0d1=256*sin(t)
    		FPACK	__DADD			;d0d1=256+256*sin(t)
    		FPACK	__DTOL			;d0=256+256*sin(t)
    		move.w	d0,(a6)+		;y
    	;
    		move.l	d4,d0			;d0d1=t
    		move.l	d5,d1
    		move.l	a4,d2			;d2d3=dt
    		move.l	a5,d3
    		FPACK	__DADD			;d0d1=t+dt
    		move.l	d0,d4			;d4d5=t+dt
    		move.l	d1,d5
    	next

    ;画面モードを変更
    	move.w	#3,-(sp)		;ファンクションキー表示なし
    	move.w	#14,-(sp)
    	DOS	_CONCTRL
    	move.w	d0,function_mode
    	move.w	#1,-(sp)		;768x512グラフィックあり
    	move.w	#16,-(sp)
    	DOS	_CONCTRL
    	move.w	d0,screen_mode
    	addq.l	#8,sp

    ;カーソルOFF
    	IOCS	_B_CUROFF

    ;スーパーバイザモード
    	supervisormode

    ;スプライトコントローラ初期化
    	move.w	#28+4,SPRC_H_BACK_END	;水平バックポーチ終了カラム。R02+4
    	move.w	#255,SPRC_H_FRONT_END	;水平フロントポーチ終了カラム。255。ウェイトは省略
    	move.w	#40,SPRC_V_BACK_END	;垂直バックポーチ終了ラスタ。R06
    	move.w	#%10101,SPRC_RESOLUTION	;解像度。--------|---|高解像度|垂直サイズ##|水平サイズ##
    	moveq.l	#0,d0
    	move.l	d0,SPRC_BG_0_X		;BG0スクロールX座標,BG0スクロールY座標
    	move.l	d0,SPRC_BG_1_X		;BG1スクロールX座標,BG1スクロールY座標
    	move.w	d0,SPRC_CONTROL		;コントロール。------|スプライト画面ON|---|BG1テキスト##|BG1表示ON|BG0テキスト##|BG0表示ON

    ;パターン4096枚定義ON
    	move.w	#$0005,$00EB0812

    ;スプライトをクリア
    	lea.l	$00EB0000,a0
    	moveq.l	#0,d0
    	move.w	#256-1,d1
    	for	d1
    		move.l	d0,(a0)+
    		move.l	d0,(a0)+
    	next

    ;パターンをクリア
    	moveq.l	#0,d0
    	moveq.l	#0,d2			;バンク
    	do
    		move.w	d2,$00EB0814		;バンク番号
    		lea.l	$00EB8000,a0
    		move.w	#32768/8-1,d1
    		for	d1
    			move.l	d0,(a0)+
    			move.l	d0,(a0)+
    		next
    		add.w	#$0100,d2
    	while	<cmp.w #$0F00,d2>,ls

    ;テキストエリアにパターンを敷き詰める
    	lea.l	$00EB4000,a0		;開始位置(0,0)
    	moveq.l	#0,d4			;パターン番号上位4bit<<12
    	move.w	#1<<8,d5		;パレットブロック<<8。パレットブロック1から
    	moveq.l	#0,d6			;パターン番号下位8bit
    	do
    		moveq.l	#16-1,d3		;Y方向ループ上位16回
    		for	d3
    			moveq.l	#4-1,d2			;Y方向ループ下位4回
    			for	d2
    				moveq.l	#64-1,d1		;X方向ループ64回
    				for	d1
    					move.w	d4,d0			;パターン番号上位4bit<<12
    					add.w	d5,d0			;パレットブロック<<8
    					add.w	d6,d0			;パターン番号下位8bit
    					move.w	d0,(a0)+
    					addq.b	#1,d6			;パターン番号下位8bit
    				next
    			next
    			add.w	#1<<12,d4		;パターン番号上位4bit<<12
    		next
    		add.w	#1<<8,d5		;パレットブロック<<8
    	while	<cmp.w #2<<8,d5>,ls	;パレットブロック2まで

    ;スプライト表示ON
    ;	BG0にテキストエリア0、BG1にテキストエリア1を割り当てて表示
    	move.w	#SPRC_SPRITE_ON|SPRC_BG_1_TEXT_1|SPRC_BG_1_ON|SPRC_BG_0_TEXT_0|SPRC_BG_0_ON,SPRC_CONTROL
    	ori.w	#VICON_SPON_MASK,VICON_VISIBLE
    	move.w	#%00_00_01_10_11_10_01_00,VICON_PRIORITY

    ;パレットを設定する
    	movehsv	104,31,31,VICON_TSPALET+2*$11	;青。BG0。スプライトパレット$11
    	movehsv	152,31,31,VICON_TSPALET+2*$21	;紫。BG1。スプライトパレット$21
    	movehsv	8,31,31,VICON_TSPALET+2*1	;赤。テキスト画面。テキストパレット1
    	movehsv	56,31,31,VICON_GPALET+2*1	;緑。グラフィック画面。グラフィックパレット1

    ;開始位置までスクロールする
    	lea.l	orbit,a0
    	move.w	(a0),SPRC_BG_0_X	;BG0を動かす
    	move.w	2(a0),SPRC_BG_0_Y
    	move.w	4*(orbit_length*1/4)(a0),SPRC_BG_1_X	;BG1を動かす
    	move.w	4*(orbit_length*1/4)+2(a0),SPRC_BG_1_Y
    	move.w	4*(orbit_length*2/4)(a0),CRTC_TEXT_X	;テキスト画面を動かす
    	move.w	4*(orbit_length*2/4)+2(a0),CRTC_TEXT_Y
    	move.w	4*(orbit_length*3/4)(a0),CRTC_GRAPHIC_X_0	;グラフィック画面を動かす
    	move.w	4*(orbit_length*3/4)+2(a0),CRTC_GRAPHIC_Y_0

    ;文字を描く
    	lea.l	moji(pc),a0		;a0=文字
    	moveq.l	#2,d7			;2=S,1=T,0=G
    	for	d7
    	;文字コードを取り出す。SJISに限る
    		moveq.l	#0,d0
    		moveq.l	#0,d1
    		move.b	(a0)+,d0		;sh
    		move.b	(a0)+,d1		;sl
    	;94区94点の通し番号を求める
    	;	((sh - (sh < 0xe0 ? 0x81 : 0xe0 - (0xa0 - 0x81))) * 188 +
    	;	 (sl - (sl < 0x80 ? 0x40 : 0x80 - (0x7f - 0x40))))
    		moveq.l	#$81,d2
    		if	<cmp.b #$E0,d0>,hs
    			moveq.l	#$E0-($A0-$81),d2
    		endif
    		sub.b	d2,d0
    		moveq.l	#$40,d2
    		if	<cmp.b #$80,d1>,hs
    			moveq.l	#$80-($7F-$40),d2
    		endif
    		sub.b	d2,d1
    		mulu.w	#188,d0
    		add.w	d1,d0
    	;9区から15区までないので詰める
    		if	<cmp.w #94*(16-1),d0>,hs	;16区～
    			sub.w	#94*(16-9),d0		;16区→9区
    		endif
    	;フォントアドレスを求める
    		mulu.w	#3*24,d0
    		add.l	#$00F40000,d0		;24x24
    		movea.l	d0,a1
    	;点を並べる
    		moveq.l	#1,d3			;色
    		move.w	#512-12,d2		;Y座標
    		moveq.l	#24-1,d6		;24ライン
    		for	d6
    			move.w	#512-12,d1		;X座標
    			moveq.l	#3-1,d5			;3バイト
    			for	d5
    				move.b	(a1)+,d0
    				moveq.l	#8-1,d4			;8ドット
    				for	d4
    					add.b	d0,d0
    					if	cs
    						if	<cmp.w #1,d7>,hi	;2=S
    							bsr	sp_pset
    						elif	eq			;1=T
    							bsr	tx_pset
    						else				;0=G
    							bsr	gr_pset
    						endif
    					endif
    					addq.w	#1,d1			;X座標を進める
    				next
    			next
    			sub.w	#24,d1			;X座標を戻して
    			addq.w	#1,d2			;Y座標を進める
    		next
    	next

    ;ハイポトロコイドを描く
    ;	t=0
    ;	for i=1 to fn0
    ;		pset(floor(ox+s*(Rr*cos(t)+d*cos(Rrr*t))),
    ;		     floor(oy-s*(Rr*sin(t)-d*sin(Rrr*t))))
    ;		t=t+dt
    ;	next
    	moveq.l	#0,d4			;d4d5=t
    	moveq.l	#0,d5
    	move.l	int_fn0,d7
    	forlong	d7
    		movem.l	dbl_Rrr,d0-d1		;d0d1=Rrr
    		move.l	d4,d2			;d2d3=t
    		move.l	d5,d3
    		FPACK	__DMUL			;d0d1=Rrr*t
    		movea.l	d0,a4			;a4a5=Rrr*t
    		movea.l	d1,a5
    		FPACK	__COS			;d0d1=cos(Rrr*t)
    		movem.l	dbl_d,d2-d3		;d2d3=d
    		FPACK	__DMUL			;d0d1=d*cos(Rrr*t)
    		movea.l	d0,a2			;a2a3=d*cos(Rrr*t)
    		movea.l	d1,a3
    		move.l	d4,d0			;d0d1=t
    		move.l	d5,d1
    		FPACK	__COS			;d0d1=cos(t)
    		movem.l	dbl_Rr,d2-d3		;d2d3=Rr
    		FPACK	__DMUL			;d0d1=Rr*cos(t)
    		move.l	a2,d2			;d2d3=d*cos(Rrr*t)
    		move.l	a3,d3
    		FPACK	__DADD			;d0d1=Rr*cos(t)+d*cos(Rrr*t)
    		movem.l	dbl_s,d2-d3		;d2d3=s
    		FPACK	__DMUL			;d0d1=s*(Rr*cos(t)+d*cos(Rrr*t))
    		movem.l	dbl_ox,d2-d3	;d2d3=ox
    		FPACK	__DADD			;d0d1=ox+s*(Rr*cos(t)+d*cos(Rrr*t))
    		FPACK	__DFLOOR		;d0d1=floor(ox+s*(Rr*cos(t)+d*cos(Rrr*t)))
    		FPACK	__DTOL			;d0=floor(ox+s*(Rr*cos(t)+d*cos(Rrr*t)))
    		movea.l	d0,a0			;a0=floor(ox+s*(Rr*cos(t)+d*cos(Rrr*t))) X座標
    	;
    		move.l	a4,d0
    		move.l	a5,d1			;d0d1=Rrr*t
    		FPACK	__SIN			;d0d1=sin(Rrr*t)
    		movem.l	dbl_d,d2-d3		;d2d3=d
    		FPACK	__DMUL			;d0d1=d*sin(Rrr*t)
    		movea.l	d0,a2			;a2a3=d*sin(Rrr*t)
    		movea.l	d1,a3
    		move.l	d4,d0			;d0d1=t
    		move.l	d5,d1
    		FPACK	__SIN			;d0d1=sin(t)
    		movem.l	dbl_Rr,d2-d3		;d2d3=Rr
    		FPACK	__DMUL			;d0d1=Rr*sin(t)
    		move.l	a2,d2			;d2d3=d*sin(Rrr*t)
    		move.l	a3,d3
    		FPACK	__DSUB			;d0d1=Rr*sin(t)-d*sin(Rrr*t)
    		movem.l	dbl_s,d2-d3		;d2d3=s
    		FPACK	__DMUL			;d0d1=s*(Rr*sin(t)-d*sin(Rrr*t))
    		move.l	d0,d2			;d2d3=s*(Rr*sin(t)-d*sin(Rrr*t))
    		move.l	d1,d3
    		movem.l	dbl_oy,d0-d1	;d0d1=oy
    		FPACK	__DSUB			;d0d1=oy-s*(Rr*sin(t)-d*sin(Rrr*t))
    		FPACK	__DFLOOR		;d0d1=floor(oy-s*(Rr*sin(t)-d*sin(Rrr*t)))
    		FPACK	__DTOL			;d0=floor(oy-s*(Rr*sin(t)-d*sin(Rrr*t)))
    		movea.l	d0,a1			;a1=floor(oy-s*(Rr*sin(t)-d*sin(Rrr*t))) Y座標
    	;
    		move.l	a0,d1
    		move.l	a1,d2
    		moveq.l	#1,d3
    		bsr	sp_pset
    		bsr	tx_pset
    		bsr	gr_pset
    	;
    		move.l	d4,d0			;d0d1=t
    		move.l	d5,d1
    		movem.l	dbl_dt,d2-d3		;d2d3=dt
    		FPACK	__DADD			;d0d1=t+dt
    		move.l	d0,d4			;d4d5=t+dt
    		move.l	d1,d5
    	next

    ;動かす
    	lea.l	orbit,a0
    	movea.l	a0,a1
    	lea.l	4*(orbit_length*1/4)(a0),a2
    	lea.l	4*(orbit_length*2/4)(a0),a3
    	lea.l	4*(orbit_length*3/4)(a0),a4
    	lea.l	orbit_end-orbit(a0),a5
    	moveq.l	#0,d1			;-1=停止中,0=動作中,1=コマ送り
    	dostart
    		ifand	<tst.l d1>,mi,<cmp.b #13,d0>,eq	;停止中にENTERキーが押されたとき
    			moveq.l	#0,d1			;動作中にする
    		elif	<tst.b d0>,ne		;停止中にENTER以外のキーが押されたか、動作中に何かキーが押されたとき
    			moveq.l	#1,d1			;コマ送りにする
    		endif
    	start
    		do
    		while	<btst.b #MFP_G_VDISP_BIT,MFP_GPDR>,eq	;垂直表示期間を待つ
    		do
    		while	<btst.b #MFP_G_VDISP_BIT,MFP_GPDR>,ne	;垂直帰線期間を待つ
    		if	<tst.l d1>,pl		;動作中またはコマ送りのとき
    			if	ne			;コマ送りのとき
    				moveq.l	#-1,d1			;停止中にする
    			endif
    			move.w	(a1)+,SPRC_BG_0_X	;BG0を動かす
    			move.w	(a1)+,SPRC_BG_0_Y
    			if	<cmpa.l a5,a1>,eq
    				movea.l	a0,a1
    			endif
    			move.w	(a2)+,SPRC_BG_1_X	;BG1を動かす
    			move.w	(a2)+,SPRC_BG_1_Y
    			if	<cmpa.l a5,a2>,eq
    				movea.l	a0,a2
    			endif
    			move.w	(a3)+,CRTC_TEXT_X	;テキスト画面を動かす
    			move.w	(a3)+,CRTC_TEXT_Y
    			if	<cmpa.l a5,a3>,eq
    				movea.l	a0,a3
    			endif
    			move.w	(a4)+,CRTC_GRAPHIC_X_0	;グラフィック画面を動かす
    			move.w	(a4)+,CRTC_GRAPHIC_Y_0
    			if	<cmpa.l a5,a4>,eq
    				movea.l	a0,a4
    			endif
    		endif
    		bsr	inkey0
    	whileand	<cmp.b #27,d0>,ne,<cmp.b #3,d0>,ne	;ESCまたはCTRL+Cが押されるまで繰り返す

    ;スプライト表示OFF
    	move.w	#$0000,SPRC_CONTROL
    	andi.w	#.notw.VICON_SPON_MASK,VICON_VISIBLE

    ;パターン4096枚定義OFF
    	move.w	#$0000,$00EB0812
    	move.w	#$0000,$00EB0814

    ;ユーザモード
    	usermode

    ;カーソルON
    	IOCS	_B_CURON

    ;画面モードを復元
    	move.w	screen_mode,-(sp)
    	move.w	#16,-(sp)
    	DOS	_CONCTRL
    	move.w	function_mode,-(sp)
    	move.w	#14,-(sp)
    	DOS	_CONCTRL
    	addq.l	#8,sp

    ;終了
    exit:
    	DOS	_EXIT

    moji:		.dc.w	'Ｓ','Ｔ','Ｇ'

    ;エラー終了
    error:
    	pea.l	usage(pc)
    	DOS	_PRINT
    	addq.l	#4,sp
    	move.w	#1,-(sp)
    	DOS	_EXIT2

    usage:		.dc.b	'>hypotrochoid.x R r d f',13,10
    		.dc.b	'                               既定値  最小値   最大値',13,10
    		.dc.b	'  R  定円の半径(整数)              97     r+1  1000000',13,10
    		.dc.b	'  r  動円の半径(整数)              47       1      R-1',13,10
    		.dc.b	'  d  動円の中心から点までの距離    37       1  1000000',13,10
    		.dc.b	'  f  1周(≠1周期)の点の数(整数)   720       1  1000000',13,10
    		.dc.b	0
    	.even

    ;sp_pset
    ;	バックグラウンド画面に点を描く
    ;	1024x1024ドットの画面が64x64個の16x16ドット(128バイト)のパターンに分割されている
    ;	画面座標(%LLLLLLSTXX,%BBBBHHYYYY)
    ;	パターン座標(%LLLLLL,%BBBBHH) パターン内座標(%STXX,%YYYY)
    ;	パターン番号%BBBBHHLLLLLL バンク番号%BBBB バンク内パターン番号%HHLLLLLL
    ;	ワードアドレス$00EB8000+%HHLLLLLLSYYYYT0 ワード内ビット番号%XX00^%1100
    ;<d1.w:X座標。0～1023。範囲外のとき何もしない
    ;<d2.w:Y座標。0～1023。範囲外のとき何もしない
    ;<d3.w:パレットコード。0～15。下位4bitを使う
    sp_pset:
    	ifand	<cmp.w #1023,d1>,ls,<cmp.w #1023,d2>,ls
    		push	d1-d5/a0
    		moveq.l	#%1111,d4		;d1.w=%LLLLLLSTXX
    		moveq.l	#%1111,d5		;d2.w=%BBBBHHYYYY
    		and.w	d4,d3			;d3.w=%PPPP
    		and.w	d1,d4			;d4.l=%STXX
    		and.w	d2,d5			;d5.l=%YYYY
    		lsr.w	#4,d1			;d1.w=%LLLLLL
    		lsr.w	#4,d2			;d2.w=%BBBBHH
    		lsl.w	#6,d2			;d2.w=%BBBBHH000000
    		or.w	d2,d1			;d1.w=%BBBBHHLLLLLL パターン番号
    		move.w	d1,$00EB0814		;%BBBB バンク番号
    		moveq.l	#0,d2
    		move.b	d1,d2			;d2.l=%HHLLLLLL
    		lsl.b	#5,d4			;d4.b=%TXX00000,x=S
    		addx.w	d2,d2			;d2.l=%HHLLLLLLS
    		lsl.w	#4,d2			;d2.l=%HHLLLLLLS0000
    		or.w	d5,d2			;d2.l=%HHLLLLLLSYYYY
    		add.b	d4,d4			;d4.b=%XX000000,x=T
    		addx.w	d2,d2			;d2.l=%HHLLLLLLSYYYYT
    		add.w	d2,d2			;d2.l=%HHLLLLLLSYYYYT0
    		lea.l	$00EB8000,a0
    		adda.l	d2,a0			;a0=$00EB8000+%HHLLLLLLSYYYYT0 ワードアドレス
    		lsr.b	#4,d4			;d4.b=%XX00
    		eor.b	#%1100,d4		;d4.b=%XX00^%1100 ワード内ビット番号
    		move.w	(a0),d2			;ワードを読み出す
    		ror.w	d4,d2			;目的の位置を下位4bitへ移動する
    		and.w	#%1111111111110000,d2	;下位4bitを消す
    		or.w	d3,d2			;下位4bitにパレットコードを入れる
    		rol.w	d4,d2			;元の位置に戻す
    		move.w	d2,(a0)			;ワードを書き戻す
    		pop
    	endif
    	rts

    tx_pset:
    	ifand	<cmp.w #1023,d1>,ls,<cmp.w #1023,d2>,ls
    		push	d0-d3/a0
    		move.w	CRTC_ACCESS,-(sp)
    		move.w	#$0200,CRTC_ACCESS	;マスクON,同時OFF
    		move.w	CRTC_MASK,-(sp)
    		lea.l	$00E60000,a0		;プレーン3から
    		ext.l	d2
    		lsl.l	#7,d2			;y*128
    		adda.l	d2,a0
    		moveq.l	#15,d0
    		and.w	d1,d0			;xの下位4bit
    		move.w	#$8000,d2
    		lsr.w	d0,d2			;書き込むビットだけ1
    		not.w	d2			;書き込むビットだけ0
    		move.w	d2,CRTC_MASK
    		lsr.w	#4,d1
    		add.w	d1,d1			;x/16*2
    		adda.w	d1,a0
    		ror.w	#4,d3			;bit3を最上位に
    		moveq.l	#4-1,d2
    		for	d2
    			add.w	d3,d3			;押し出す
    			subx.w	d0,d0			;全ビットに展開
    			move.w	d0,(a0)			;書き込む
    			suba.l	#$00020000,a0
    		next
    		move.w	(sp)+,CRTC_MASK
    		move.w	(sp)+,CRTC_ACCESS
    		pop
    	endif
    	rts

    gr_pset:
    	ifand	<cmp.w #1023,d1>,ls,<cmp.w #1023,d2>,ls
    		push	d1-d2/a0
    		lea.l	$00C00000,a0
    		swap.w	d2
    		clr.w	d2
    		lsr.l	#5,d2			;y*2048
    		adda.l	d2,a0
    		add.w	d1,d1			;x*2
    		move.w	d3,(a0,d1.w)
    		pop
    	endif
    	rts

    	.data
    	.even
    ;定数
    dbl_ox:		.dc.d	512.0		;ox 中心のX座標
    dbl_oy:		.dc.d	512.0		;oy 中心のY座標
    dbl_RR:		.dc.d	510.0		;RR 表示半径
    ;引数
    int_R:		.dc.l	97		;R 定円の半径
    int_r:		.dc.l	47		;r 動円の半径
    dbl_d:		.dc.d	37.0		;d 動円の中心から点までの距離
    int_f:		.dc.l	720		;f 1周(≠1周期)の点の数

    	.bss
    	.even
    ;引数で決まる値
    dbl_R:		.ds.d	1		;R 定円の半径
    dbl_r:		.ds.d	1		;r 動円の半径
    int_Rr:		.ds.l	1		;Rr=R-r 定円の中心から動円の中心までの距離
    dbl_Rr:		.ds.d	1		;Rr=R-r 定円の中心から動円の中心までの距離
    dbl_Rrr:	.ds.d	1		;Rrr=(R-r)/r 点の速度
    int_n0:		.ds.l	1		;n0=r/gcd(R-r,r) 周期
    int_fn0:	.ds.l	1		;fn0=f*n0 n0周(=1周期)の点の数
    dbl_s:		.ds.d	1		;s=RR/(R-r+d) 倍率
    dbl_f:		.ds.d	1		;f 1周(≠1周期)の点の数
    dbl_dt:		.ds.d	1		;dt=2*pi/f 角度の増分

    ;保存した画面モード
    function_mode:	.ds.w	1
    screen_mode:	.ds.w	1

    ;スクロールの軌道
    orbit:		.ds.w	2*720
    orbit_end:

    	.text

    ;----------------------------------------------------------------
    ;文字コードが0でないキーを入力する。押されていなくても待たない
    ;>d0.l:文字コード。0=押されていない
    inkey0::
    	dostart
    		IOCS	_B_KEYINP		;キーバッファから取り除く
    		break	<tst.b d0>,ne		;文字コードが0でないキーが押されたとき終了
    	start
    		IOCS	_B_KEYSNS		;キーバッファを先読みする
    	while	<tst.l d0>,ne		;何か押されているとき繰り返す
    	and.l	#$000000FF,d0		;文字コード
    	rts

    ;----------------------------------------------------------------
    ;空白を読み飛ばす
    ;<a0.l:文字列
    ;>d0.l:最初の空白以外の文字または0
    ;>a0.l:最初の空白以外の文字または0の位置
    ;>z:ne=空白以外の文字がある,eq=空白以外の文字がない
    nextword::
    	moveq.l	#0,d0
    	do
    		move.b	(a0)+,d0		;次の文字
    		break	eq			;0ならば終了
    		redo	<cmp.b #' ',d0>,eq	;' 'ならば繰り返す
    	whileand	<cmp.b #9,d0>,hs,<cmp.b #13,d0>,ls	;\t\n\v\f\rならば繰り返す
    	subq.l	#1,a0			;進み過ぎた分戻る
    	tst.l	d0
    	rts

    	.end

STUDIO KAMADA
Copyright © 1999-2026 Makoto Kamada