#author("2023-04-30T13:49:35+09:00","","")
* DMAの応用例 [#yf70394b]
ウィンドウとDMA(HBLANK)機能を使ったサンプルコードです。メトロイドの序盤で表示されるライト表示をほぼ再現しています。構成は以下の通りです。~

-[[github:https://github.com/akkera102/gbadev-ja/tree/main/doc21%20DMA%E3%81%AE%E5%BF%9C%E7%94%A8]]
#ref(1.png,nolink)

- mode0
| bg0 | ASCII文字 | 256x256 | 16色 |
| bg1 | マスク    | 256x256 | 16色 |
| bg2 | ステージ  | 512x256 | 16色 |

ステージは横長なので始点を変えたり、ウィンドウの内部と外部にどれを表示させるかの設定を加えています。

 	REG_BG2HOFS = 120;
 	REG_BG2VOFS = 64;
 
 	REG_WIN0H  = 0;
 	REG_WIN0V  = SCREEN_HEIGHT;
 	REG_WININ  = WIN_0_BG0 | WIN_0_BG2;
 	REG_WINOUT = WIN_0_BG0 | WIN_0_BG1;

 /* Create an array of horizontal offsets for a circular window.
 *	The offsets are to be copied to REG_WINxH each HBlank, either 
 *	by HDMA or HBlank isr. Offsets provided by modified 
 *	Bresenham's circle routine (of course); the clipping code is not
 *	optional.
 *
 *	\param x0	X-coord of circle center.
 *	\param y0	Y-coord of circle center.
 *	\param rr	Circle radius.
 */
 
 u16 BgWinh[SCREEN_HEIGHT+1] ALIGN(4);
 
 IWRAM_CODE void BgCreateWindowCircleDma(s32 x0, s32 y0, s32 rr)
 {
 	// Zero clear
 	for(vs32 i=0; i<SCREEN_HEIGHT+1; i++)
 	{
 		BgWinh[i] = 0;
 	}
 
 
 	s32 x=0, y=rr, d=1-rr;
 	u32 tmp;
 
 	while(y >= x)
 	{
 		// Side octs
 		tmp  = BgClamp(x0 + y, 0, SCREEN_WIDTH+1);
 		tmp += BgClamp(x0 - y, 0, SCREEN_WIDTH+1) << 8;
 
 		// o4, o7
 		if(BgInRange(y0-x, 0, SCREEN_HEIGHT))
 		{
 			BgWinh[y0 - x]= tmp;
 		}
 
 		// o0, o3
 		if(BgInRange(y0+x, 0, SCREEN_HEIGHT))
 		{
 			BgWinh[y0 + x]= tmp;
 		}
 
 		// Change in y: top/bottom octs
 		if(d >= 0)
 		{
 			tmp  = BgClamp(x0 + x, 0, SCREEN_WIDTH+1);
 			tmp += BgClamp(x0 - x, 0, SCREEN_WIDTH+1) << 8;
 
 			// o5, o6
 			if(BgInRange(y0-y, 0, SCREEN_HEIGHT))
 			{
 				BgWinh[y0 - y]= tmp;
 			}
 
 			// o1, o2
 			if(BgInRange(y0+y, 0, SCREEN_HEIGHT))
 			{
 				BgWinh[y0 + y]= tmp;
 			}
 
 			d -= 2 * (--y);
 		}
 
 		d += 2 * (x++) + 3;
 	}
 
 /*
 	for(vs32 i=0; i<SCREEN_HEIGHT+1; i++)
 	{
 		TRACE("%d: %4x\n", i, BgWinh[i]);
 	}
 	for(;;){}
 */
 
 	REG_DMA3CNT = 0;
 	REG_DMA3SAD = (u32)&BgWinh[1];
 	REG_DMA3DAD = (u32)&REG_WIN0H;
 	REG_DMA3CNT = 1 | (DMA_DST_RELOAD | DMA_REPEAT | DMA_HBLANK | DMA_ENABLE);
 }
 //---------------------------------------------------------------------------
 IWRAM_CODE s32 BgClamp(s32 val, s32 min, s32 max)
 {
 	if(val < min)
 	{
 		return min;
     }
 
 	if(val > max)
 	{
 		return max;
 	}
 
 	return val;
 }
 //---------------------------------------------------------------------------
 IWRAM_CODE bool BgInRange(s32 x, s32 min, s32 max)
 {
 	return ((x)>=(min)) && ((x)<(max)) ? TRUE : FALSE;
 }

** 出典元 [#pb4ac969]
- Tonc

** 履歴 [#j0abcb62]
- 2023/04/30


トップ   一覧 検索 最終更新   ヘルプ   最終更新のRSS