*************************************************************************
* PIC FILE LOADER Main Routine
* pic.sとmpic.sから呼び出される
* Oh!X 1990/2月号のPICローダーのＣ言語版を元に作成
*（できる限りの高速化を行なっているがPIC.Rにかなわない）
*（しかしメモリー使用量が少ないのがこのルーチンの特徴）
* この中では画面の初期化はしないので外部で行なうこと
*************************************************************************
* 1993/10/05 : さらに高速化と思ったけどあまり速くならずに省メモリー化
*************************************************************************

	.include	defines.mac

*************************************************************************

	.if	0
	
	move.w	#5,-(sp)
	move.w	#16,-(sp)
	DOS	_CONCTRL	* 512*512/65536
	addq.w	#4,sp
	
	IOCS	_ONTIME		* BIOS start -> current time
	move.l	d0,-(sp)
	
	move.l	#fname,a0	* picfile名
	move.l	#GRAM,a1	* 書き込み top address
	bsr	pic_sub
	
	IOCS	_ONTIME		* BIOS start -> current time
	move.l	(sp)+,d1
	sub.l	d1,d0		* 1/100sec
	move.l	d0,time
	
	clr.w	-(sp)
	DOS	_EXIT2
	
	.data
	.xdef	time
time:	.dc.l	0
fname:	.dc.b	'occult22.pic',0
	.text
	.endif

*************************************************************************

SIZE_OF_X	equ	512
SIZE_OF_Y	equ	512
SIZE_OF_BUFF	equ	4096	* 必ず２の倍数のこと
				* テストの結果4096以上はほとんど変わらない
*************************************************************************
* a0 = pic filename
* a1 = pic画像展開バッファーアドレス（スーパーバイザー領域も可能）

	.xdef	pic_sub
pic_sub:
	move.l	a1,adrs			* 書き込み top address
	
	* picfile open
	clr.w	-(sp)
	move.l	a0,-(sp)
	DOS	_OPEN
	addq.w	#6,sp
	move.l	d0,handle		* ファイルハンドル(long word)
	bmi	pret			* <0 : open error
	
	movem.l	d3-d7/a3-a6,-(sp)
	
	SUPERMODE			* SuperVisor mode
	move.l	d0,lusp			* save user mode stack pointer
	move.l	sp,lssp			* エラー処理のため
	
	* 定数セット（高速化のため）
	moveq.l	#0,d1			* c=0 (d1.w)
	move.l	d1,d4			* bit_len=0
	move.l	d1,d5			* color_p=0
	move.l	#tbl_color,a4		* table[].color
	move.l	#tbl_next,a5		* table[].next
	move.l	#tbl_prev,a6		* table[].prev
	
	bsr	color_cash_init		* 色キャッシュ初期化
	
	move.l	#buff_end,a2		* buff_p (buff_end for first data load)
	* d6.l = *buff_p
	move.l	adrs,d2			* (GRAM) line top address
	move.l	d2,a3			* (GRAM) top address
	
	bsr	dataload		* ヘッダー読みだし
	bsr	chk_header		* ヘッダーチェック(if err goto p_err)
	moveq.l	#0,d4			* ビットデータがd6.wに入っていない印
	move.l	a2,d0			* ヘッダーを読み出した結果がword境界でない場合
	bclr.l	#0,d0			* データーを読み出してword境界にする
	beq	l1			* すでにword境界にある
	move.b	(a2)+,d6
	lsl.l	#8,d6
	moveq.l	#8,d4
	
l1:	* d3.h.w = x_wid , d3.l.w=x count
	* a0 = y_widのGRAMアドレス
	
	bsr	expand			* 展開！（ここがメイン）
	* 正常終了ならここに戻ってくる
	moveq.l	#0,d0			* ok symbol
peret:
	move.l	d0,d1			* push d0
	move.l	lusp,a1			* to user mode
	USERMODE			* to user mode
	move.l	d1,d0			* pop d0
	
	movem.l	(sp)+,d3-d7/a3-a6
	
	* picfile close
	move.l	d0,d1			* push d0
	move.w	handle+2,-(sp)		* wordでファイルハンドルを渡すから
	DOS	_CLOSE
	addq.w	#2,sp
	move.l	d1,d0			* pop d0
pret:
	rts

p_err:	* エラーが発生するとここに飛んでくる
	move.l	lssp,sp			* stack 補正
	moveq.l	#1,d0			* error code = 1
	bra	peret

*************************************************************************
* 色キャッシュ初期化

color_cash_init:
	move.l	a4,a0		* table[].color
	move.l	a5,a1		* table[].next
	move.l	a6,a2		* table[].prev
	moveq.l	#0,d0		* i=0
cci1:
	clr.w	(a0)+		* color=0
	subq.w	#1,d0
	move.b	d0,(a1)+	* next=i-1
	addq.w	#2,d0
	move.b	d0,(a2)+	* prev=i+1
	cmp.w	#128,d0
	bne	cci1
	move.b	#127,(a5)	* table[0].next=127
	move.b	#0,127(a6)	* table[127].prev=0
	rts

*************************************************************************
* byte/word境界を問わないword読みとり

WORD	macro	aa,dd
	move.b	(aa)+,dd
	lsl.w	#8,dd
	move.b	(aa)+,dd
	endm

*************************************************************************
* ヘッダーチェック

chk_header:
* 大幅に処理方法を変えたため、ヘッダーサイズがSIZE_OF_BUFFを越えると
* おかしくなる。しかしそんな大きいヘッダーは存在しないだろうからよしとする。
	* 識別子チェック
	* if (bit_load(8)!='P'||bit_load(8)!='I'||bit_load(8)!='C') goto error
	cmp.b	#'P',(a2)+
	bne	p_err
	cmp.b	#'I',(a2)+
	bne	p_err
	cmp.b	#'C',(a2)+
	bne	p_err
	
hr1:	* while ((c=bit_load(8))!=0x1a) putchar(c);
	cmp.b	#$1a,(a2)+
	bne	hr1		* ここではputchar(c)しない
hr2:	* while (bit_load(8)!=0);
	tst.b	(a2)+
	bne	hr2
	
	* if (bit_load(16)!=0) goto error
	tst.b	(a2)+
	bne	p_err
	tst.b	(a2)+
	bne	p_err
	
	* 有効色ビット数チェック
	* このpicload()は32768色PICのみ対応
	WORD	a2,d7
	cmp.w	#15,d7		* 有効色ビット数 = 15 ?
	bne	p_err		* no = error
	
	* Ｘ幅チェック
	WORD	a2,d7		* x_wid
	cmp.w	#SIZE_OF_X,d7	* x_wid>SIZE_OF_X ?
	bgt	p_err		* yes = error
	move.w	d7,d3
	swap	d3
	move.w	d7,d3		* d3.l.w=x count
	addq.w	#1,d3		* +1 for first count in expand
	
	* Ｙ幅チェック
	WORD	a2,d7		* y_wid
	cmp.w	#SIZE_OF_Y,d7	* y_wid>SIZE_OF_Y ?
	ble	hr3		* no
	move.w	#SIZE_OF_Y,d7	* yes : y_wid=SIZE_OF_Y
hr3:
	and.l	#$ffff,d7	* for longword
	lsl.l	#8,d7
	lsl.l	#2,d7		* y_wid*1024
	add.l	a3,d7		* +GRAM top address
	move.l	d7,a0		* y_widのGRAMアドレス
	rts

*************************************************************************
* マクロ定義
*   少しでも速くするためサブルーチンをやめてマクロにする
*************************************************************************
* データ読み出しマクロ

DREAD	macro
local	l1
	cmp.l	#buff_end,a2	* buff_p==buff_end ?
	bne	l1		* no
	bsr	dataload	* yes = data load
l1:
	move.w	(a2)+,d6	* d6.w=*buff_p++ (longwordよりwordの方が早い）
	moveq.l	#16,d4		* bit_len=16 (word)
	endm

*************************************************************************
* １ビットデータチェック

BIT_LOAD1	macro		* -> CY flag
local	bl1_2
	tst.w	d4		* bit_len==0 ?
	bne	bl1_2		* no
	DREAD			* 次のデータを読み出す
bl1_2:
	subq.w	#1,d4		* bit_len--
	add.w	d6,d6		* lsl.w	#1,d6	* -> CY
	endm

*************************************************************************
* １６ビット以下データロード

BIT_LOAD16	macro
local	bl16_2,bl16_3,bl16_4,bl16_5
* d0.w = size <=16 -> d7.w/.l
	moveq.l	#0,d7		* a=0
	
	cmp.w	d0,d4		* bit_len>=size ?
	bge	bl16_3		* yes
	
	tst.w	d4		* d6.wのデータがない？
	beq	bl16_5		* yes : ない -> 次のデータを読み出して続行
	
	* まず現在d6.wに残っているビットを読み出す
	sub.w	d4,d0		* (size-=bit_len)>0
	subq.w	#1,d4		* -1 for dbf
bl16_4:
	add.w	d6,d6		* lsl.w	#1,d6
	addx.w	d7,d7		* roxl.w #1,d7
	dbf	d4,bl16_4

bl16_5:	* d6.wのデータがなくなった
	DREAD			* 次のデータを読み出して続行

bl16_3:	* d6.wからsizeビット分読み出す
	sub.w	d0,d4		* bit_len-=size
	subq.w	#1,d0		* -1 for dbf
bl16_2:
	add.w	d6,d6		* lsl.w	#1,d6
	addx.w	d7,d7		* roxl.w #1,d7 & d7==0 ?
	dbf	d0,bl16_2	* dbccはフラグを壊さない
	endm

*************************************************************************
* サイズ可変ビットデータロード
* d0.w = size -> d7.l

BIT_LOAD	macro
local	bl5,bl13,bl12,bl3,bl2,bl1
	moveq.l	#1,d7		* a=1 : 最上位ビットを１にするため
bl5:
	cmp.w	d4,d0		* while (size>bit_len) {
	ble	bl3		* while end
	
	* まずd6.wから取り出せるだけのビットを取り出す
	sub.w	d4,d0		* size-=bit_len
	bra	bl12
bl13:
	add.w	d6,d6		* lsl.w	#1,d6
	addx.l	d7,d7		* roxl.l #1,d7
bl12:
	dbf	d4,bl13
	DREAD			* 次のデータを読み出す
	bra	bl5

bl3:	* あとは全ビットがd6.wから取り出せる
	sub.w	d0,d4		* bit_len-=size
	bra	bl1
bl2:
	add.w	d6,d6		* lsl.w	#1,d6
	addx.l	d7,d7		* roxl.l #1,d7
bl1:
	dbf	d0,bl2
	endm

*************************************************************************
* Wyle符号化された位置＝変化点距離の展開（最大符号：１８＋長さ：１８ビット）
*   1 〜 2	0x		全体２ビット	長さ１ビット
*   3 〜 6	10xx		４		２
*   7 〜 14	110xxx		６		３
*  15 〜 30	1110xxxx	８		４
*  31 〜 62	11110xxxxx	１０		５
* 以後同様に長さが１８ビットまで作られる可能性がある
* これは1と0の数（＝１の数＋１）が以後に続く距離を表わすビット数に等しい

READ_LEN	macro		* -> d7.l
local	rl1
	moveq.l	#0,d0		* a=0
rl1:	* while (bit_load(1)!=0) a++;
	addq.w	#1,d0		* a++（最初はa=1）
	BIT_LOAD1
	bcs	rl1		* cy=1
	* return(bit_load(a)+(1<<a)-1);
	BIT_LOAD		* bit_load(a)+(1<<a) -> d7.l
	subq.l	#1,d7		* -1
	endm

*************************************************************************
* 新しい色の登録

NEW_COLOR	macro
* -> d1.w = c
	moveq.l	#15,d0
	BIT_LOAD16		* -> c (d7.w)
	move.w	d7,d1		* d1=c
	* color_p=table[color_p].prev;
	move.b	(a6,d5.w),d5
	* table[color_p].color=c;
	move.w	d5,d0
	add.w	d0,d0		* *2 for word[] access
	move.w	d1,(a4,d0.w)
	endm

*************************************************************************
* 色取得

GET_COLOR	macro
* -> d1.w = c
local	gc1
	moveq.l	#7,d0
	BIT_LOAD16		* -> idx (d7.w)
	
	cmp.w	d7,d5		* if (color_p!=idx) {
	beq	gc1
	moveq.l	#0,d1		* for long word 拡張
	move.w	d1,d0		* 同上
	
	* table[table[idx].prev].next=table[idx].next;
	move.b	(a6,d7.w),d1	* table[idx].prev
	move.b	(a5,d7.w),d0	* table[idx].next;
	move.b	d0,(a5,d1.w)	* table[].next=table[idx].next;
	
	* table[table[idx].next].prev=table[idx].prev;
	move.b	d1,(a6,d0.w)	* table[].prev=table[idx].prev;
	
	* table[table[color_p].prev].next=idx;
	move.b	(a6,d5.w),d1	* table[color_p].prev
	move.b	d7,(a5,d1.w)	* table[].next=idx;
	
	move.b	d1,(a6,d7.w)	* table[idx].prev=table[color_p].prev;
	move.b	d7,(a6,d5.w)	* table[color_p].prev=idx;
	move.b	d5,(a5,d7.w)	* table[idx].next=color_p;
	move.b	d7,d5		* color_p=idx;
	
gc1:	* return(table[idx].color);
	add.w	d7,d7		* *2 for word[] access
	move.w	(a4,d7.w),d1
	endm

*************************************************************************
* 連鎖の展開

EXPAND_CHAIN	macro
local	ec0,ec1,ec2,ec3,ec4,ec5,ec_ret
	move.w	d1,d0
	addq.w	#1,d0		* 境界色なので輝度ビット（ビット０）を１にする
	move.l	a3,a1
	subq.w	#2,a1		* a1=GRAM address（先に＋２されているので）
	move.w	d3,d7		* d7=x count
ec1:
	BIT_LOAD1
	bcc	ec5		* 0x
	* 1x
	BIT_LOAD1
	bcc	ec3		* 10 : x±0
	* 11 = x+1
	addq.w	#2,a1		* GRAM +1 dot
	subq.w	#1,d7		* x+1 (x count-1)
	beq	ec_ret		* x count ==0 -> 連鎖終了
ec3:
	lea	1024(a1),a1	* next line GRAM address
	cmp.l	a0,a1		* y-address>=y_wid-address ?
	bge	ec1		* yes : no-pset
	move.w	d0,(a1)		* pset(x,y,c)
	bra	ec1		* 次の連鎖へ

ec5:	* 0x
	BIT_LOAD1
	bcc	ec0		* 00 : x±2
	* 01 : x-1
	subq.w	#2,a1		* GRAM -1 dot
	addq.w	#1,d7		* x-1 (x count+1)
ec2:
	lea	1024(a1),a1	* next line GRAM address
	cmp.l	a0,a1		* y-address>=y_wid-address ?
	bge	ec1		* yes : no-pset
	move.w	d0,(a1)		* pset(x,y,c)
	bra	ec1		* 次の連鎖へ

ec0:	* 00 : x±2
	* if (bit_load(1)==0) return;
	BIT_LOAD1
	bcc	ec_ret
	
	* if (bit_load(1)==0) x-=2; else x+=2;
	subq.w	#4,a1		* GRAM -2 dot
	addq.w	#2,d7		* x-=2 (x count+2)
	BIT_LOAD1
	bcc	ec2		* ==0
	addq.w	#8,a1		* GRAM +2 dot（先に-2されているから）
	subq.w	#4,d7		* x+=2（x count-1：先に-2されているから）
	bne	ec2		* x count > 0
	* x count==0 -> 連鎖終了
ec_ret:
	endm

*************************************************************************
* ＰＩＣ展開

expand:
	* 変化点までの距離を求める
	READ_LEN		* d7.l=read_len()
	
e6:	* 次のドット／ラインへ
	subq.w	#1,d3		* x count -1 == 0 ?
	bne	e2		* no
	* x count == 0 -> 次のラインへ
	add.l	#1024,d2	* next line top address
	cmp.l	a0,d2		* y-address >= y_wid-address ?（y 終わり ?）
	bge	e_ret		* yも終わりなら終了
	* 次のラインの先頭へ
	move.l	d2,a3
	swap	d3		* d3.h.w=x_wid -> d3.l.w
	move.w	d3,d0		* w_wid -> d0.w
	swap	d3		* d3.h.w=x_wid
	move.w	d0,d3		* d3.l.w=x count
e2:
	* 最後の１点の手前までの処理
	subq.l	#1,d7
	beq	e4		* 最後の１点
	
	* 境界判定
	* 今度打つ点の所にすでに輝度ビット色がある場合、それは境界点である
	* このときは輝度ビットを消すと同時にその色を今後の色とする
	lsr.w	(a3)		* 輝度ビットを消してみる -> CY
	bcc	e7		* 輝度ビットなし -> 今の色をそのまま入れる
	lsl.w	(a3)		* 色を戻して
	move.w	(a3)+,d1	* それを今後の色とする
	bra	e6
e7:
	move.w	d1,(a3)+	* pset(x,y,c)
	bra	e6

**************************	* 一番遅い
	.if	0
	bclr.b	#0,1(a3)	* 輝度ビットチェック＆消し
	beq	e7		* 輝度ビットなし（色は変更しない）
	move.w	(a3)+,d1	* それを今後の色とする
	bra	e6
e7:
	move.w	d1,(a3)+	* pset(x,y,c)
	bra	e6
	.endif
**************************	* 次に遅い
	.if	0
	swap	d1
	move.w	(a3),d1
	bclr.l	#0,d1
	bne	e7		* 輝度ビットあり
	swap	d1
	move.w	d1,(a3)		* pset(x,y,c)
e7:
	addq.w	#2,a3
	bra	e6
	.endif
**************************

e4:	* 最後の１点の処理
	BIT_LOAD1		* bit_load(1)
	bcs	e31		* ==1
	NEW_COLOR		* -> d1
	bra	e32
e31:
	GET_COLOR		* -> d1
e32:
	add.w	d1,d1		* lsl.w #1,d1 = 色
	move.w	d1,(a3)+	* pset(x,y,c)
	
	* if (bit_load(1)!=0) expand_chain(x,y,c|1);
	BIT_LOAD1
	bcc	expand		* 次の点へ
	EXPAND_CHAIN		* 連鎖展開
	bra	expand		* 次の点へ
e_ret:
	rts

*************************************************************************
* ファイルからのデータ読みだし

dataload:
	* ret=read(handle,buff,SIZE_OF_BUFF)
	move.l	d0,-(sp)		* push d0
	move.l	#buff,a2		* buff_p=buff
	pea	SIZE_OF_BUFF.w		* read size
	move.l	a2,-(sp)		* read address
	move.w	handle+2,-(sp)		* file pointer
	DOS	_READ			* file read
	lea	10(sp),sp		* stack 補正
	tst.l	d0			* error check
	bmi	p_err			* ret<0 = error
	move.l	(sp)+,d0		* pop d0
	rts

*************************************************************************
* ワークエリア

	.bss
* 色テーブル
tbl_color:
	.ds.w	128
tbl_next:
	.ds.b	128
tbl_prev:
	.ds.b	128

* スタックポインター
lusp:	.ds.l	1
lssp:	.ds.l	1

* 書き込みアドレス
adrs:	.ds.l	1

* ファイルハンドル
handle:	.ds.l	1

* ファイルバッファー
buff:	.ds.w	SIZE_OF_BUFF/2
buff_end:
	.even

*************************************************************************
	.end
