ウィンドウとDMA(HBLANK)機能を使ったサンプルコードです。メトロイドの序盤で表示されるライト表示をほぼ再現しています。構成は以下の通りです。
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)®_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; }