diff --git a/desmume/src/GPU.cpp b/desmume/src/GPU.cpp index 877f1801a..678134bcd 100644 --- a/desmume/src/GPU.cpp +++ b/desmume/src/GPU.cpp @@ -2364,7 +2364,10 @@ void GPU::_spriteRender(u8 * dst, u8 * dst_alpha, u8 * typeTab, u8 * prioTab) //NOT TESTED: if (dispCnt->OBJ_BMP_2D_dim) // 256*256 + { + //verified by heroes of mana FMV intro src = (u8 *)MMU_RenderMapToLCD(gpu->sprMem + (((spriteInfo->TileIndex&0x3E0) * 64 + (spriteInfo->TileIndex&0x1F) *8 + ( y << 8)) << 1)); + } else // 128 * 512 src = (u8 *)MMU_RenderMapToLCD(gpu->sprMem + (((spriteInfo->TileIndex&0x3F0) * 64 + (spriteInfo->TileIndex&0x0F) *8 + ( y << 8)) << 1)); } @@ -3042,6 +3045,20 @@ void GPU_ligne(NDS_Screen * screen, u16 l) GPU * gpu = screen->gpu; GPU_tempScanline_valid = false; + //here is some setup which is only done on line 0 + if(l == 0) { + //this is speculative. the idea is as follows: + //whenever the user updates the affine start position regs, it goes into the active regs immediately + //(this is handled on the set event from MMU) + //maybe it shouldnt take effect until the next hblank or something.. + //this is a based on a combination of: + //heroes of mana intro FMV + //SPP level 3-8 rotoscale room + //NSMB raster fx backdrops + //bubble bobble revolution classic mode + gpu->refreshAffineStartRegs(); + } + //cache some parameters which are assumed to be stable throughout the rendering of the entire line gpu->currLine = (u8)l; u16 mosaic_control = T1ReadWord((u8 *)&gpu->dispx_st->dispx_MISC.MOSAIC, 0); @@ -3134,6 +3151,42 @@ bool gpu_loadstate(std::istream* is) return !is->fail(); } +u32 GPU::getAffineStart(int layer, int xy) +{ + if(xy==0) return affineInfo[layer-2].x; + else return affineInfo[layer-2].y; +} + +void GPU::setAffineStartWord(int layer, int xy, u16 val, int word) +{ + u32 curr = getAffineStart(layer,xy); + if(word==0) curr = (curr&0xFFFF0000)|val; + else curr = (curr&0x0000FFFF)|(((u32)val)<<16); + setAffineStart(layer,xy,curr); +} + +void GPU::setAffineStart(int layer, int xy, u32 val) +{ + if(xy==0) affineInfo[layer-2].x = val; + else affineInfo[layer-2].y = val; + refreshAffineStartRegs(); +} + +void GPU::refreshAffineStartRegs() +{ + for(int num=2;num<=3;num++) + { + BGxPARMS * parms; + if (num==2) + parms = &(dispx_st)->dispx_BG2PARMS; + else + parms = &(dispx_st)->dispx_BG3PARMS; + + parms->BGxX = affineInfo[num-2].x; + parms->BGxY = affineInfo[num-2].y; + } +} + void gpu_UpdateRender() { int x = 0, y = 0; diff --git a/desmume/src/GPU.h b/desmume/src/GPU.h index 70b0c0bb4..019d3d3fe 100644 --- a/desmume/src/GPU.h +++ b/desmume/src/GPU.h @@ -761,6 +761,15 @@ struct GPU void __setFinalColorBck(u16 color, u8 x, bool opaque); + void setAffineStart(int layer, int xy, u32 val); + void setAffineStartWord(int layer, int xy, u16 val, int word); + u32 getAffineStart(int layer, int xy); + void refreshAffineStartRegs(); + + struct AffineInfo { + AffineInfo() : x(0), y(0) {} + u32 x, y; + } affineInfo[2]; void renderline_checkWindows(u16 x, bool &draw, bool &effect) const; diff --git a/desmume/src/MMU.cpp b/desmume/src/MMU.cpp index 6fee00b3e..9ec5e7253 100644 --- a/desmume/src/MMU.cpp +++ b/desmume/src/MMU.cpp @@ -1556,6 +1556,23 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val) // Address is an IO register switch(adr) { + case REG_DISPA_BG2XL: MainScreen.gpu->setAffineStartWord(2,0,val,0); break; + case REG_DISPA_BG2XH: MainScreen.gpu->setAffineStartWord(2,0,val,1); break; + case REG_DISPA_BG2YL: MainScreen.gpu->setAffineStartWord(2,1,val,0); break; + case REG_DISPA_BG2YH: MainScreen.gpu->setAffineStartWord(2,1,val,1); break; + case REG_DISPA_BG3XL: MainScreen.gpu->setAffineStartWord(3,0,val,0); break; + case REG_DISPA_BG3XH: MainScreen.gpu->setAffineStartWord(3,0,val,1); break; + case REG_DISPA_BG3YL: MainScreen.gpu->setAffineStartWord(3,1,val,0); break; + case REG_DISPA_BG3YH: MainScreen.gpu->setAffineStartWord(3,1,val,1); break; + case REG_DISPB_BG2XL: SubScreen.gpu->setAffineStartWord(2,0,val,0); break; + case REG_DISPB_BG2XH: SubScreen.gpu->setAffineStartWord(2,0,val,1); break; + case REG_DISPB_BG2YL: SubScreen.gpu->setAffineStartWord(2,1,val,0); break; + case REG_DISPB_BG2YH: SubScreen.gpu->setAffineStartWord(2,1,val,1); break; + case REG_DISPB_BG3XL: SubScreen.gpu->setAffineStartWord(3,0,val,0); break; + case REG_DISPB_BG3XH: SubScreen.gpu->setAffineStartWord(3,0,val,1); break; + case REG_DISPB_BG3YL: SubScreen.gpu->setAffineStartWord(3,1,val,0); break; + case REG_DISPB_BG3YH: SubScreen.gpu->setAffineStartWord(3,1,val,1); break; + case REG_DISPA_DISP3DCNT: { MainScreen.gpu->dispx_st->dispA_DISP3DCNT.val = val; @@ -2194,6 +2211,31 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val) switch(adr) { + case REG_DISPA_BG2XL: + MainScreen.gpu->setAffineStart(2,0,val); + return; + case REG_DISPA_BG2YL: + MainScreen.gpu->setAffineStart(2,1,val); + return; + case REG_DISPB_BG2XL: + SubScreen.gpu->setAffineStart(2,0,val); + return; + case REG_DISPB_BG2YL: + SubScreen.gpu->setAffineStart(2,1,val); + return; + case REG_DISPA_BG3XL: + MainScreen.gpu->setAffineStart(3,0,val); + return; + case REG_DISPA_BG3YL: + MainScreen.gpu->setAffineStart(3,1,val); + return; + case REG_DISPB_BG3XL: + SubScreen.gpu->setAffineStart(3,0,val); + return; + case REG_DISPB_BG3YL: + SubScreen.gpu->setAffineStart(3,1,val); + return; + case 0x04000600: GFX_FIFOcnt(val); return;