gxclip_ex.s 11.8 KB
/*---------------------------------------------------------------------*
	Copyright (C) 1997, Nintendo.
	
	File		gxclip_ex.s
	Coded    by	Yoshitaka Yasumoto.	Dec 22, 1997.

	$Id: gxclip_ex.s,v 1.1.1.1 2002/05/02 03:29:11 blythe Exp $
 *---------------------------------------------------------------------*/

 #!Reserved  (0,11,12,22,23,24,25,26,27,31)
 #!Reserved  (v0,v1,v29,v30,v31)
			
	#---------------------------------------------------------------------
	#  ライトコードのオーバーレイ
	#	gxlight_ex.s のライト処理コードをロードする.
	#	caseEX_XfmLight と同じアドレスにする必要がある.
	#---------------------------------------------------------------------
caseEX_XfmLight:
		_li	(sys0, RSP_SUBMOD_OVERLAY_LIGHTING)
		j	LoadOverlay
		_li	(sys1, ovlyEX_XfmLight)

	#---------------------------------------------------------------------
	#   クリッピング処理
	#	flat,v1,v2 を頂点とする 3 角形に対してクリップ処理を行なう
	#	RSP_WORK_CLIPBUF_0,1 にそれぞれ 10 個分の Vtx Ptr 保持領域
	#	を設ける. EX マイクロコードは 頂点数が 32 個しかないので
	#	RSP_SAVE_POINTS 領域に空きがあるので, その領域を Buffer と
	#	して使用する.
	#---------------------------------------------------------------------
  FixedAssign(v0,    1)		# gxsetup からの入力
  FixedAssign(v1,    2)		# gxsetup からの入力
  FixedAssign(v2,    3)		# gxsetup からの入力
  FixedAssign(flat,  4)		# gxsetup からの入力
  FixedAssign(fogon, 7)		# gxvtx_ex 用レジスタ
  FixedAssign(dest2, 8)		# gxvtx_ex 用レジスタ
  FixedAssign(cflag, 10)	# gxvtx_ex 用レジスタ
  FixedAssign(lstat, 13)	# gxvtx_ex 用レジスタ
  FixedAssign(dest,15)		# gxvtx_ex 用レジスタ
  FixedAssign(cliptest_save, 29)
  FixedAssign(return_save, 30)
  FixedAssign(clipbuf, 18)
  Assign(plane,   5)
		#------ Clipping 処理の開始 ------
		#
		#  $31 を $30 へ保存する
		#
caseEX_Clipping:
		_mov	(return_save, return)

		#------ ClipBuf の初期化 ------
		#
		#  plane は 20 から 0 まで 4 ずつ変化し, これによって CC のマスク値と
		#  クリップ面と辺の交差判定式の各項の値を取得する
		#
caseEX_Clipping0:
		_liu	(plane,  20)			# Clipping Plane 選択
		_liu	(clipbuf, 6)			# ClipBuf へのポインタ
		_liu	(dest, RSP_WORK_CLIPVTX)	# Clipping で生成され
							# る頂点Cache
		#------ ClipBuf の初期化 ------
		sh	v0,   RSP_SUBMOD_EX_CLIPBUF-6(clipbuf)	# v0
		sh	v1,   RSP_SUBMOD_EX_CLIPBUF-4(clipbuf)	# v1
		sh	v2,   RSP_SUBMOD_EX_CLIPBUF-2(clipbuf)	# v2
		sh	zero, RSP_SUBMOD_EX_CLIPBUF-0(clipbuf)	# End Mark

		#------ ClipTest 値の保存(再 setup において使用) ------
		#
		#  処理の途中で頂点が 3 個未満になったとき, Clip_EX_Return に
		#  飛ぶが, このときに cliptest_save を書き込むことの対策
		#	NEARCLIP_ON  0x30304040
		#	NEARCLIP_OFF 0x30304080
		#
		lw	cliptest_save, RSP_SUBMOD_EX_CLIPTEST(zero)
  EndAssign(v0, 1)
  FixedAssign(num,    1)	# gxvtx_ex 用レジスタ
  FixedAssign(src,   14)	# gxvtx_ex 用レジスタ
  Assign(clipmask,    9)
  Assign(ccsave,     16)
  Assign(ibufp,      17)
  FixedAssign(obufp, 21)
EXClip_InitPlane:
		#------ CC のマスク値の取得 ------
		lw	clipmask, RSP_SUBMOD_EX_CLIPMASK(plane)
	
		#------ 最終 CC の取得 ------
		#
		#  最初の頂点と隣り合う頂点=最終頂点 ここでは v2
		#
		lw	ccsave, oRSP_POINT_CC(v2)
		and	ccsave, ccsave, clipmask
	
		#------ ClipBuf のポインタの取得 ------
		#
		#  クリップ面毎にバッファの In,Out を交換する
		#    clipbuf は 6 <-> RSP_SUBMOD_CLIPBUF_SZ+6 と変化
		#
		addi	ibufp,   clipbuf, -6
		xori	clipbuf, clipbuf, (RSP_SUBMOD_EX_CLIPBUF_SZ+6)^6
		addi	obufp,   clipbuf, -6
		
		#------ CC を比較し変化を調べる ------
		#
		#  クリップ面に対応する CC を辺の両端の頂点組ごとに比較する.
		#  異なっていた場合, クリップ面と辺が交差することになる.
		#
EXClip_NextVtx:
		lhu	v1, RSP_SUBMOD_EX_CLIPBUF(ibufp) # 頂点ポインタの取得
		addi	ibufp, ibufp, 2			# ClipBuf の加算
		beq	v1, zero, EXClip_NextPlane	# v1 が 0 なら次の面へ
		lw	sys0, oRSP_POINT_CC(v1)		# cc の取得
		and	sys0, sys0,   clipmask		# cc をマスク
		beq	sys0, ccsave, EXClip_EntryVtx	# cc が同じなら Jump
		_mov	(ccsave, sys0)			# cc のセーブ

		#------ 新しい頂点の生成(v1 と v2 の間) ------
		#
		#  同次座標系において交差位置(内分比 n)を計算する.
		#	n = (x1-w1)/((x1-x2)-(w1-w2))
		#
  Assign(selp,  v2)
  Assign(seln,  v3)
  Assign(vtx1f, v4)
  Assign(vtx1i, v5)
  Assign(vtx2f, v6)
  Assign(vtx2i, v7)
  Assign(topf,  v8)
  Assign(topi,  v9)
  Assign(botf, v10)
  Assign(boti, v11)
  Assign(v1s, 19)
EXClip_NewVtx:
		#------ vv1 を内側 v2 を外側とする ------
		beq	ccsave, zero, EXClip_NewVtx0
		_mov	(v1s, v1)
		_mov	(v1s, v2)
		_mov	(v2,  v1)
EXClip_NewVtx0:
		sll	sys0, plane, 1		# 2 倍する 0,8,16,...
		ldv	selp[0], RSP_LSTAT_CLIPSELECT(sys0)
		ldv	vtx1f[0], oRSP_POINT_XF(v1s)
		ldv	vtx1i[0], oRSP_POINT_XI(v1s)
		ldv	vtx2f[0], oRSP_POINT_XF(v2)
		ldv	vtx2i[0], oRSP_POINT_XI(v2)
		#------ 分子分母の計算 ------
		vmudh	seln, selp, _0xffff	# selp=[1 0 0 -1] のとき
		vmudn	topf, vtx1f, selp
		vmadh	topi, vtx1i, selp	# top=[x1 0 0 -w1]
		vmadn	botf, vtx2f, seln
		vmadh	boti, vtx2i, seln	# bot=[x1-x2 0 0 w2-w1]
  EndAssign(selp, v2)
  EndAssign(seln, v3)
  Assign(vconstTmp, v25)
		vaddc	topf, topf, topf[0q]	lqv	vconstTmp[0], RSP_LSTAT_VCONST_TMP(zero)
		vadd	topi, topi, topi[0q]	
		vaddc	botf, botf, botf[0q]
		vadd	boti, boti, boti[0q]
		vaddc	topf, topf, topf[1h]
		vadd	topi, topi, topi[1h]	# top[3]=(x1-w1)
		vaddc	botf, botf, botf[1h]
		vadd	boti, boti, boti[1h]	# bot[3]=(x1-x2)-(w1-w2)
		#  スケールファクタの取得
  Assign(wsclf, v2)
  Assign(wscli, v3)
			vor	vtmp, boti, _0x0001	# 非 0 にする
		vrcph	wscli[3], boti[3]
		vrcpl	wsclf[3], botf[3]
		vrcph	wscli[3], _0x0000
		#  頂点合わせ+絶対値計算
			vabs	vtmp,  vtmp,  _0x0002	# vtmp[3]=((wscli[3]>0)?2:-2)
		vmudn	wsclf, wsclf, vtmp[3]
		vmadh	wscli, wscli, vtmp[3]
		#  1 未満にまるめる
		veq	wscli, wscli, _0x0000	# if   wscl >= 1.0
		vmrg	wsclf, wsclf, _0xffff	# then wscl = 0.99999
  EndAssign(wscli, v3)
		#  スケールファクタを乗ずる
		vmudl	vtmp,  botf,  wsclf[3]
		vmadm	boti,  boti,  wsclf[3]
		vmadn	botf,  vzero, _0x0000
		#  Newton 法を使用し逆数計算を行なう 
		#	vrcph/l で求めるのは 1/2X の値. (R=1/X)
		#	1/X = R*(2-R*X) = R/2*(4+R/2*X*(-4))
  Assign(rbotf, v12)
  Assign(rboti, v13)
		vrcph	rboti[3], boti[3]
		vrcpl	rbotf[3], botf[3]
		vrcph	rboti[3], _0x0000	# R/2
#if	1
		vmudl	vtmp,  rbotf, botf
		vmadm	vtmp,  rboti, botf
		vmadn	botf,  rbotf, boti
		vmadh	boti,  rboti, boti	# R/2*X
		vmudh	vtmp,  vone,  _0x0004
		vmadn	botf,  botf,  _0xfffc
		vmadh	boti,  boti,  _0xfffc	# 4+R/2*X*(-4)
		vmudl	vtmp,  rbotf, botf
		vmadm	vtmp,  rboti, botf
		vmadn	rbotf, rbotf, boti
		vmadh	rboti, rboti, boti	# R/2*(4+R/2*X*(-4))
#else
		vmudn	rbotf, rbotf, _0x0002
		vmadh	rboti, rboti, _0x0002	# R
		vmudl	vtmp,  rbotf, botf
		vmadm	vtmp,  rboti, botf
		vmadn	botf,  rbotf, boti
		vmadh	boti,  rboti, boti	# R*X
		vmudh	vtmp,  vone,  _0x0002
		vmadn	botf,  botf,  _0xffff
		vmadh	boti,  boti,  _0xffff	# 2-R*X
		vmudl	vtmp,  rbotf, botf
		vmadm	vtmp,  rboti, botf
		vmadn	rbotf, rbotf, boti
		vmadh	rboti, rboti, boti	# R*(2-R*X)
#endif
  EndAssign(vconstTmp, v25)
  EndAssign(botf, v10)
  EndAssign(boti, v11)
  Assign(nf, v10)
  Assign(ni, v11)
  Assign(st1, v25)
  Assign(st2, v26)
		#  n=top/bot を求める
		vmudl	vtmp, topf, rbotf		luv	st2[0], oRSP_POINT_R(v2)
		vmadm	vtmp, topi, rbotf		llv	st2[8], oRSP_POINT_S(v2)
		vmadn	nf,   topf, rboti		luv	st1[0], oRSP_POINT_R(v1s)
		vmadh	ni,   topi, rboti		llv	st1[8], oRSP_POINT_S(v1s)
  EndAssign(v1s, 19)
  EndAssign(topf, v8)
  EndAssign(topi, v9)
  EndAssign(rbotf, v12)
  EndAssign(rboti, v13)
		#------ スケールファクタを乗ずる ------
		vmudl	vtmp, nf, wsclf[3]
		vmadm	ni,   ni, wsclf[3]
		vmadn	nf,   nf, _0x0000
  EndAssign(wsclf, v2)
		#------ n をクランプする ------
		#  0x0001 から 0xffff までに納める
		#
		vlt	ni,   ni, _0x0001
		vmrg	nf,   nf, _0xffff
		vsubc	vtmp, nf, _0x0001
		vge	ni,   ni, _0x0000
		vmrg	nf,   nf, _0x0001
  Assign(negnf,   v2)
		#------ 1-n の計算 ------
		vmudn	negnf, nf, _0xffff
  EndAssign(ni, v11)
  FixedAssign(vout12f, v23)
  FixedAssign(vout12i, v24)
		#
		#  新頂点座標の計算 v1*(1-n)+v2*n
		#
		vmudl	vtmp,    vtx2f, nf[3]
		vmadm	vtmp,    vtx2i, nf[3]
		vmadl	vtmp,    vtx1f, negnf[3]
		vmadm	vout12i, vtx1i, negnf[3]
		vmadn	vout12f, vzero, _0x0000
  EndAssign(vtx1f, v4)
  EndAssign(vtx1i, v5)
  EndAssign(vtx2f, v6)
  EndAssign(vtx2i, v7)
		#  新頂点のアトリビュート値の計算  [R|G|B|A|S|T|-|-]
  FixedAssign(st12, v22)
		vmudm	vtmp, st2,  nf[3]
		vmadm	st12, st1,  negnf[3]
  EndAssign(st1, v25)
  EndAssign(st2, v26)
  EndAssign(nf,    v10)
  EndAssign(negnf, v2)
		#
		#  gxvtx_ex と一致するように調整
		#    out12f(v23)
		#    out12i(v24)
		#    fogon(7)  =0
		#    num(1)    =2
		#    dest(3)   頂点キャッシュバッファ(VTX 処理内で +80 される)
		#    st12(v22) gxvtx_ex 内で変化無いので return 後再設定する
		#
		#    GetTrans で以下が取得できる
		#	lstat(13),vpscale(v16),vptrans(v17),txscale(v18),dest2(8)
		#
		#    GetTrans 後 G_VTX_Return へ Jump する.
		#
		_li	(fogon, 0)
		_li	(num,   2)
		sh	dest, RSP_SUBMOD_EX_CLIPBUF(obufp)
		j	caseEX_G_VTX_GetTrans
		_li	(return, caseEX_G_VTX_Return+0x8000)	# return<0 なら vtx 処理後,ここへ戻る
  FixedAssign(vscn12i, v25)
  FixedAssign(vscn12f, v26)
  FixedAssign(vcolor,  v3)
		#------ 残りパラメータの書き込み ------
caseEX_ClipRet:
#ifndef	NO_CLAMP_Z
		slv	vscn12i[0],  24-80(dest)  # Xs,Ys1
#else
		sdv	vscn12i[0],  24-80(dest)  # Xs,Ys,Zs1
#endif
		ssv	vscn12f[4],  30-80(dest)  # Zsf1
		suv	st12[0],     16-80(dest)  # R,G,B,A
		slv	st12[8],     20-80(dest)  # S,T
#ifndef	NO_CLAMP_Z
		ssv	vcolor[4],   28-80(dest)  # Zs1
#endif
		addi	dest,  dest,  -40
		addi	obufp, obufp, 2
  EndAssign(st12, v22)
  EndAssign(vout12f, v23)
  EndAssign(vout12i, v24)
  EndAssign(vscn12i, v25)
  EndAssign(vscn12f, v26)
  EndAssign(vcolor,  v3)
		
EXClip_EntryVtx:
		#------ 頂点 v1 が画面内ならバッファに登録 ------
		bne	ccsave, zero, EXClip_NextVtx	# 画面外なら次の頂点へ
		_mov	(v2, v1)			# v1 のセーブ
		sh	v2, RSP_SUBMOD_EX_CLIPBUF(obufp)# ClipBuf への登録
		j	EXClip_NextVtx
		addi	obufp, obufp, 2
EXClip_NextPlane:
		#------ 頂点が無くなったら終了する ------
		#
		#  obufp が clipbuf に到達しないのは頂点が 3 個未満の時
		#
		sub	sys0, obufp, clipbuf
		bltz	sys0, Clip_EX_Return
		#------ 次のクリップ面へ ------
		sh	zero, RSP_SUBMOD_EX_CLIPBUF(obufp)   # End Mark の設定
		lhu	v2,   RSP_SUBMOD_EX_CLIPBUF-2(obufp) # 最終 Vtx の取得
		bne	plane, zero, EXClip_InitPlane
		addi	plane, plane, -4
  EndAssign(num,       1)
  EndAssign(src,      14)
  EndAssign(dest,     15)
  EndAssign(lstat,    13)
  EndAssign(fogon,     7)
  EndAssign(dest2,     8)
  EndAssign(cflag,    10)
  EndAssign(plane,     5)
  EndAssign(clipmask,  9)
  EndAssign(ccsave,   16)
  EndAssign(ibufp,    17)
	
  FixedAssign(v0, 1)
  FixedAssign(vptr, v2)		# gxsetup_ex.s で共用
  FixedAssign(quart, v3)	# gxsetup_ex.s で共用
  FixedAssign(vtx1, v4)		# gxsetup_ex.s で共用
		#------ Setup ルーチンにおける Clip 判定を無効にする ------
		#
		#  RSP_SUBMOD_CLIPTEST を 0 にすると Clip 処理が無効になる
		#  有効にするには cliptest_save に保存しておいた値を書き戻す
		#
		sw	zero, RSP_SUBMOD_EX_CLIPTEST(zero)	# 0 クリア

		#------ クリップ処理後の 3 角形の描画 ------
Clip_EX_Draw:	lhu	v0, RSP_SUBMOD_EX_CLIPBUF-6(clipbuf)
		lhu	v1, RSP_SUBMOD_EX_CLIPBUF-4(clipbuf)
		lhu	v2, RSP_SUBMOD_EX_CLIPBUF-2(obufp)
		mtc2	v0, vptr[10]			vor	quart, vzero, _0x4000
		mtc2	v1, vtx1[12]
		jal	Setup_EX_Clipped
		mtc2	v2, vptr[14]
		bne	obufp, clipbuf, Clip_EX_Draw
		addi	clipbuf, clipbuf, 2
			
		#------ Setup ルーチンにおける Clip 判定を有効にする ------
Clip_EX_Return:	jr	return_save
		sw	cliptest_save, RSP_SUBMOD_EX_CLIPTEST(zero)
		
  EndAssign(v0,   1)		# gxsetup_ex.s で共用
  EndAssign(v1,   2)		# gxsetup_ex.s で共用
  EndAssign(v2,   3)		# gxsetup_ex.s で共用
  EndAssign(flat, 4)		# gxsetup_ex.s で共用
  EndAssign(clipbuf, 18)
  EndAssign(obufp,   21)
  EndAssign(cliptest_save, 29)
  EndAssign(return_save, 30)
  EndAssign(vptr, v2)		# gxsetup_ex.s で共用
  EndAssign(quart, v3)		# gxsetup_ex.s で共用
  EndAssign(vtx1, v4)		# gxsetup_ex.s で共用
	
/*======== End of gxclip_ex.s ========*/