diff --git a/desmume/src/GPU.c b/desmume/src/GPU.c index c4ba1dffa..4d126f46e 100644 --- a/desmume/src/GPU.c +++ b/desmume/src/GPU.c @@ -148,11 +148,15 @@ void GPU_resortBGs(GPU *gpu) memset(gpu->sprWin[i],0, 256); // we don't need to check for windows here... - gpu->LayersEnable[0] = gpu->dispBG[0] && cnt->BG0_Enable && !(gpu->dispCnt.bits.BG0_3D && (gpu->core==0)) ; - gpu->LayersEnable[1] = gpu->dispBG[1] && cnt->BG1_Enable; - gpu->LayersEnable[2] = gpu->dispBG[2] && cnt->BG2_Enable; - gpu->LayersEnable[3] = gpu->dispBG[3] && cnt->BG3_Enable; - gpu->LayersEnable[4] = gpu->dispOBJ && cnt->OBJ_Enable; +// if we tick boxes, invisible layers become invisible & vice versa +#define OP ^ ! +// if we untick boxes, layers become invisible +//#define OP && + gpu->LayersEnable[0] = gpu->dispBG[0] OP(cnt->BG0_Enable && !(gpu->dispCnt.bits.BG0_3D && (gpu->core==0))); + gpu->LayersEnable[1] = gpu->dispBG[1] OP(cnt->BG1_Enable); + gpu->LayersEnable[2] = gpu->dispBG[2] OP(cnt->BG2_Enable); + gpu->LayersEnable[3] = gpu->dispBG[3] OP(cnt->BG3_Enable); + gpu->LayersEnable[4] = gpu->dispOBJ OP(cnt->OBJ_Enable); // KISS ! lower priority first, if same then lower num for (i=0;iOBJ_Tile_1D) { /* 1-d sprite mapping */ - /* TODO: better comment (and understanding btw 8S) */ - gpu->sprBlock = 5 + cnt->OBJ_Tile_1D_Bound ; + // boundary : + // core A : 32k, 64k, 128k, 256k + // core B : 32k, 64k, 128k, 128k + gpu->sprBoundary = 5 + cnt->OBJ_Tile_1D_Bound ; if((gpu->core == GPU_SUB) && (cnt->OBJ_Tile_1D_Bound == 3)) { - gpu->sprBlock = 7; + gpu->sprBoundary = 7; } gpu->spriteRender = sprite1D; } else { /* 2d sprite mapping */ - gpu->sprBlock = 5; + // boundary : 32k + gpu->sprBoundary = 5; gpu->spriteRender = sprite2D; } if(cnt->OBJ_BMP_1D_Bound && (gpu->core == GPU_MAIN)) { - gpu->sprBMPBlock = 8; + gpu->sprBMPBoundary = 8; } else { - gpu->sprBMPBlock = 7; + gpu->sprBMPBoundary = 7; } gpu->sprEnable = cnt->OBJ_Enable; @@ -295,19 +302,18 @@ void GPU_setBGProp(GPU * gpu, u16 num, u16 p) void GPU_remove(GPU * gpu, u8 num) { - gpu->dispBG[num] = 0; + if (num == 4) gpu->dispOBJ = 0; + else gpu->dispBG[num] = 0; GPU_resortBGs(gpu); } void GPU_addBack(GPU * gpu, u8 num) { - gpu->dispBG[num] = 1; + if (num == 4) gpu->dispOBJ = 1; + else gpu->dispBG[num] = 1; GPU_resortBGs(gpu); } -void GPU_toggleOBJ(GPU * gpu, u8 disp) { - gpu->dispOBJ = disp; -} void GPU_scrollX(GPU * gpu, u8 num, u16 v) { @@ -610,7 +616,6 @@ INLINE void renderline_setFinalColor(GPU *gpu,u32 passing,u8 bgnum,u8 *dst,u16 c //} } color = (sourceR & 0x1F) | ((sourceG & 0x1F) << 5) | ((sourceB & 0x1F) << 10) | 0x8000 ; - #undef min } T2WriteWord(dst, passing, color) ; break ; @@ -653,19 +658,24 @@ INLINE void renderline_setFinalColor(GPU *gpu,u32 passing,u8 bgnum,u8 *dst,u16 c } ; /* render a text background to the combined pixelbuffer */ -INLINE void renderline_textBG(GPU * gpu, u8 num, u8 * DST, u32 Y, u16 XBG, u16 YBG, u16 LG) +INLINE void renderline_textBG(GPU * gpu, u8 num, u8 * dst, u32 Y, u16 XBG, u16 YBG, u16 LG) { struct _BGxCNT bgCnt = gpu->bgCnt[num].bits; u16 lg = gpu->BGSize[num][0]; u16 ht = gpu->BGSize[num][1]; u16 tmp = ((YBG&(ht-1))>>3); - u8 * map = gpu->BG_map_ram[num] + (tmp&31) * 64; - u8 *dst = DST; - u8 *tile; + u8 *map = gpu->BG_map_ram[num] + (tmp&31) * 64; + u8 *tile, *pal, *line; + u16 xoff = XBG; - u8 * pal; u16 yoff; - u16 x; + u16 x = 0; + u16 xfin; + + s8 line_dir = 1; + u8 pt_xor = 0; + u8 * mapinfo; + TILEENTRY tileentry; if(tmp>31) { @@ -675,8 +685,11 @@ INLINE void renderline_textBG(GPU * gpu, u8 num, u8 * DST, u32 Y, u16 XBG, u16 Y tile = (u8*) gpu->BG_tile_ram[num]; if((!tile) || (!gpu->BG_map_ram[num])) return; /* no tiles or no map*/ xoff = XBG; + pal = ARM9Mem.ARM9_VMEM + gpu->core * ADDRESS_STEP_1KB ; + if(!bgCnt.Palette_256) /* color: 16 palette entries */ { + if (bgCnt.Mosaic_Enable){ /* test NDS: #2 of http://desmume.sourceforge.net/forums/index.php?action=vthread&forum=2&topic=50&page=0#msg192 */ @@ -684,355 +697,284 @@ INLINE void renderline_textBG(GPU * gpu, u8 num, u8 * DST, u32 Y, u16 XBG, u16 Y u8 mw = (gpu->MOSAIC & 0xF) +1 ; /* horizontal granularity of the mosaic */ u8 mh = ((gpu->MOSAIC>>4) & 0xF) +1 ; /* vertical granularity of the mosaic */ YBG = (YBG / mh) * mh ; /* align y by vertical granularity */ - yoff = ((YBG&7)<<2); - pal = ARM9Mem.ARM9_VMEM + gpu->core * ADDRESS_STEP_1KB ; - for(x = 0; x < LG;) + + xfin = 8 - (xoff&7); + for(x = 0; x < LG; xfin = min(x+8, LG)) { - u8 * mapinfo; - u16 mapinfovalue; - u8 *line; - u16 xfin; + u8 pt = 0, save = 0; tmp = ((xoff&(lg-1))>>3); mapinfo = map + (tmp&0x1F) * 2; if(tmp>31) mapinfo += 32*32*2; - mapinfovalue = T1ReadWord(mapinfo, 0); + tileentry.val = T1ReadWord(mapinfo, 0); + + line = (u8*)tile + (tileentry.bits.TileNum * 0x20) + ((tileentry.bits.VFlip)? (7*4)-yoff:yoff); - line = (u8 * )tile + ((mapinfovalue&0x3FF) * 0x20) + (((mapinfovalue)& 0x800 ? (7*4)-yoff : yoff)); - xfin = x + (8 - (xoff&7)); - if (xfin > LG) - xfin = LG; #define RENDERL(c,m) \ - if (c) renderline_setFinalColor(gpu,0,num,dst,T1ReadWord(pal, ((c) + ((mapinfovalue>>12)&0xF) * m) << 1),x,Y) ; \ + if (c) renderline_setFinalColor(gpu,0,num,dst,T1ReadWord(pal, ((c) + (tileentry.bits.Palette* m)) << 1),x,Y) ; \ dst += 2; x++; xoff++; - - if((mapinfovalue) & 0x400) + if(tileentry.bits.HFlip) { - u8 pt = 0 ; - u8 save = 0; - line += 3 - ((xoff&7)>>1); - for(; x < xfin; ) { -// XXX - if ((pt % mw) == 0) { /* only update the color we draw every mw pixels */ - if (pt & 1) { - save = (*line) & 0xF ; - } else { - save = (*line) >> 4 ; - } - } - RENDERL(save,0x10) - pt++ ; - if (!(pt % mw)) { /* next pixel next possible color update */ - if (pt & 1) { - save = (*line) & 0xF ; - } else { - save = (*line) >> 4 ; - } - } - RENDERL(save,0x10) - line--; pt++ ; - } + line_dir = -1; + pt_xor = 0; } else { - u8 pt = 0 ; - u8 save = 0; line += ((xoff&7)>>1); - - for(; x < xfin; ) { + line_dir = 1; + pt_xor = 1; + } // XXX - if (!(pt % mw)) { /* only update the color we draw every n mw pixels */ - if (!(pt & 1)) { - save = (*line) & 0xF ; - } else { - save = (*line) >> 4 ; - } + for(; x < xfin; ) { + if (!(pt % mw)) { /* only update the color we draw every n mw pixels */ + if ((pt & 1)^pt_xor) { + save = (*line) & 0xF ; + } else { + save = (*line) >> 4 ; } - RENDERL(save,0x10) - pt++ ; - if (!(pt % mw)) { /* next pixel next possible color update */ - if (!(pt & 1)) { - save = (*line) & 0xF ; - } else { - save = (*line) >> 4 ; - } - } - RENDERL(save,0x10) - line++; pt++ ; } + RENDERL(save,0x10) + pt++ ; + if (!(pt % mw)) { /* next pixel next possible color update */ + if ((pt & 1)^pt_xor) { + save = (*line) & 0xF ; + } else { + save = (*line) >> 4 ; + } + } + RENDERL(save,0x10) + line+=line_dir; pt++ ; } } } else { /* no mosaic mode */ - yoff = ((YBG&7)<<2); - pal = ARM9Mem.ARM9_VMEM + gpu->core * ADDRESS_STEP_1KB ; - for(x = 0; x < LG;) + xfin = 8 - (xoff&7); + for(x = 0; x < LG; xfin = min(x+8, LG)) { - u8 * mapinfo; - u16 mapinfovalue; - u8 *line; - u16 xfin; tmp = ((xoff&(lg-1))>>3); mapinfo = map + (tmp&0x1F) * 2; if(tmp>31) mapinfo += 32*32*2; - mapinfovalue = T1ReadWord(mapinfo, 0); + tileentry.val = T1ReadWord(mapinfo, 0); - line = (u8 * )tile + ((mapinfovalue&0x3FF) * 0x20) + (((mapinfovalue)& 0x800 ? (7*4)-yoff : yoff)); - xfin = x + (8 - (xoff&7)); - if (xfin > LG) - xfin = LG; - - if((mapinfovalue) & 0x400) + line = (u8 * )tile + (tileentry.bits.TileNum * 0x20) + ((tileentry.bits.VFlip) ? (7*4)-yoff : yoff); + + if(tileentry.bits.HFlip) { - line += 3 - ((xoff&7)>>1); + //x=xfin; continue; + line += (3 - ((xoff&7)>>1)); + line_dir = -1; for(; x < xfin; ) { -// XXX RENDERL(((*line)>>4),0x10) RENDERL(((*line)&0xF),0x10) - line--; + line += line_dir; } } else { line += ((xoff&7)>>1); + line_dir = 1; for(; x < xfin; ) { -// XXX RENDERL(((*line)&0xF),0x10) RENDERL(((*line)>>4),0x10) - line++; + line += line_dir; } } } } return; } + if(!gpu->dispCnt.bits.ExBGxPalette_Enable) /* color: no extended palette */ { yoff = ((YBG&7)<<3); - pal = ARM9Mem.ARM9_VMEM + gpu->core * ADDRESS_STEP_1KB ; - for(x = 0; x < LG;) + xfin = 8 - (xoff&7); + for(x = 0; x < LG; xfin = min(x+8, LG)) { - u8 * mapinfo; - u16 mapinfovalue; - u8 *line; - u16 xfin; - tmp = ((xoff&(lg-1))>>3); + tmp = (xoff & (lg-1))>>3; mapinfo = map + (tmp & 31) * 2; - mapinfovalue; - if(tmp > 31) mapinfo += 32*32*2; + tileentry.val = T1ReadWord(mapinfo, 0); + + line = (u8 * )tile + (tileentry.bits.TileNum*0x40) + ((tileentry.bits.VFlip) ? (7*8)-yoff : yoff); - mapinfovalue = T1ReadWord(mapinfo, 0); - - line = (u8 * )tile + ((mapinfovalue&0x3FF)*0x40) + (((mapinfovalue)& 0x800 ? (7*8)-yoff : yoff)); - xfin = x + (8 - (xoff&7)); - if (xfin > LG) - xfin = LG; - - if((mapinfovalue)& 0x400) + if(tileentry.bits.HFlip) { line += (7 - (xoff&7)); - for(; x < xfin; ) - { - RENDERL((*line),0) - line--; - } - } else - { + line_dir = -1; + } else { line += (xoff&7); - for(; x < xfin; ) - { - RENDERL((*line),0) - line++; - } + line_dir = 1; + } + for(; x < xfin; ) + { + RENDERL((*line),0) + line += line_dir; } } return; } - /* color: extended palette */ + + /* color: extended palette */ pal = ARM9Mem.ExtPal[gpu->core][gpu->BGExtPalSlot[num]]; if(!pal) return; yoff = ((YBG&7)<<3); - - for(x = 0; x < LG;) + xfin = 8 - (xoff&7); + for(x = 0; x < LG; xfin = min(x+8, LG)) { - u8 * mapinfo; - u16 mapinfovalue; - u8 * line; - u16 xfin; tmp = ((xoff&(lg-1))>>3); mapinfo = map + (tmp & 0x1F) * 2; - mapinfovalue; - if(tmp>31) mapinfo += 32 * 32 * 2; + tileentry.val = T1ReadWord(mapinfo, 0); - mapinfovalue = T1ReadWord(mapinfo, 0); - - line = (u8 * )tile + ((mapinfovalue&0x3FF)*0x40) + (((mapinfovalue)& 0x800 ? (7*8)-yoff : yoff)); - xfin = x + (8 - (xoff&7)); - if (xfin > LG) - xfin = LG; + line = (u8 * )tile + (tileentry.bits.TileNum*0x40) + ((tileentry.bits.VFlip)? (7*8)-yoff : yoff); - if((mapinfovalue)& 0x400) + if(tileentry.bits.HFlip) { line += (7 - (xoff&7)); - for(; x < xfin;) - { - /* this is was adapted */ - RENDERL((*line),0x100) - line--; - } - } else - { + line_dir = -1; + } else { line += (xoff&7); - for(; x < xfin; ) - { - /* this is was adapted */ - RENDERL((*line),0x100) - line++; - } + line_dir = 1; + } + for(; x < xfin; ) + { + RENDERL((*line),0x100) + line += line_dir; } } #undef RENDERL } -INLINE void rotBG2(GPU * gpu, u8 num, u8 * DST, u16 H, s32 X, s32 Y, s16 PA, s16 PB, s16 PC, s16 PD, u16 LG) -{ - struct _BGxCNT bgCnt = gpu->bgCnt[num].bits; - s32 x = X + (s32)PB*(s32)H; - s32 y = Y + (s32)PD*(s32)H; +// scale rot +void rot_tiled_8bit_entry(GPU * gpu, int num, int auxX, int auxY, int lg, u8 * dst, u8 * map, u8 * tile, u8 * pal) { + u8 palette_entry; + u16 tileindex, x, y, color; - s32 dx = (s32)PA; - s32 dy = (s32)PC; + tileindex = map[(auxX + auxY * lg)>>3]; + x = (auxX&7); y = (auxY&7); - s32 auxX; - s32 auxY; - - s32 lg = gpu->BGSize[num][0]; - s32 ht = gpu->BGSize[num][1]; - s32 lgmap = (lg>>3); - - u8 * map = gpu->BG_map_ram[num]; - u8 * tile = (u8 *)gpu->BG_tile_ram[num]; - u8 * dst = DST; - u8 mapinfo; - u8 coul; - u8 * pal; - u32 i; - - if((!tile)||(!map)) return; - - pal = ARM9Mem.ARM9_VMEM + gpu->core * 0x400; - for(i = 0; i < LG; ++i) - { - auxX = x>>8; - auxY = y>>8; - - if(bgCnt.PaletteSet_Wrap) - { - auxX &= (lg-1); - auxY &= (ht-1); - } - - if ((auxX >= 0) && (auxX < lg) && (auxY >= 0) && (auxY < ht)) - { - mapinfo = map[(auxX>>3) + ((auxY>>3) * lgmap)]; - coul = tile[mapinfo*64 + ((auxY&7)<<3) + (auxX&7)]; - if(coul) - renderline_setFinalColor(gpu,0,num,dst,T1ReadWord(pal, coul << 1),i,X); - } - dst += 2; - x += dx; - y += dy; - } + palette_entry = tile[(tileindex<<6)+(y<<3)+x]; + color = T1ReadWord(pal, palette_entry << 1); + if (palette_entry) + renderline_setFinalColor(gpu,0,num,dst, color,auxX,auxY); } -INLINE void extRotBG2(GPU * gpu, u8 num, u8 * DST, u16 H, s32 X, s32 Y, s16 PA, s16 PB, s16 PC, s16 PD, s16 LG) +void rot_tiled_16bit_entry(GPU * gpu, int num, int auxX, int auxY, int lg, u8 * dst, u8 * map, u8 * tile, u8 * pal) { + u8 palette_entry, palette_set; + u16 tileindex, x, y, color; + + if (!tile) return; + tileindex = T1ReadWord(map, ((auxX + auxY * lg)>>3) << 1); + palette_set = tileindex >> 12; + tileindex &= 0x3FF; + x = (palette_set & 1) ? 7 - (auxX&7) : (auxX&7); + y = (palette_set & 2) ? 7 - (auxY&7) : (auxY&7); + + palette_entry = tile[(tileindex<<6)+(y<<3)+x]; + color = T1ReadWord(pal, (palette_entry + (palette_set<<8)) << 1); + if (palette_entry) + renderline_setFinalColor(gpu,0,num,dst, color, auxX, auxY); +} + +void rot_256_map(GPU * gpu, int num, int auxX, int auxY, int lg, u8 * dst, u8 * map, u8 * tile, u8 * pal) { + u8 palette_entry; + u16 tileindex, color; + + palette_entry = map[auxX + auxY * lg]; + color = T1ReadWord(pal, palette_entry << 1); + if(palette_entry) + renderline_setFinalColor(gpu,0,num,dst, color, auxX, auxY); + +} + +void rot_BMP_map(GPU * gpu, int num, int auxX, int auxY, int lg, u8 * dst, u8 * map, u8 * tile, u8 * pal) { + u16 color; + + color = T1ReadWord(map, (auxX + auxY * lg) << 1); + if (color&0x8000) + renderline_setFinalColor(gpu,0,num,dst, color, auxX, auxY); + +} + +typedef void (*rot_fun)(GPU * gpu, int num, int auxX, int auxY, int lg, u8 * dst, u8 * map, u8 * tile, u8 * pal); + +INLINE void apply_rot_fun(GPU * gpu, u8 num, u8 * dst, u16 H, s32 X, s32 Y, s16 PA, s16 PB, s16 PC, s16 PD, u16 LG, rot_fun fun, u8 * map, u8 * tile, u8 * pal) +{ + ROTOCOORD x, y; + struct _BGxCNT bgCnt = gpu->bgCnt[num].bits; + + s32 dx = (s32)PA; + s32 dy = (s32)PC; + s32 lg = gpu->BGSize[num][0]; + s32 ht = gpu->BGSize[num][1]; + u32 i, auxX, auxY; + + if (!map) return; + x.val = X + (s32)PB*(s32)H; + y.val = Y + (s32)PD*(s32)H; + + for(i = 0; i < LG; ++i) + { + auxX = x.bits.Integer; + auxY = y.bits.Integer; + + if(bgCnt.PaletteSet_Wrap) + { + // wrap + auxX = auxX & (lg-1); + auxY = auxY & (ht-1); + } + + if ((auxX >= 0) && (auxX < lg) && (auxY >= 0) && (auxY < ht)) + fun(gpu, num, auxX, auxY, lg, dst, map, tile, pal); + dst += 2; + x.val += dx; + y.val += dy; + } +} + +INLINE void rotBG2(GPU * gpu, u8 num, u8 * dst, u16 H, s32 X, s32 Y, s16 PA, s16 PB, s16 PC, s16 PD, u16 LG) { + u8 * map = gpu->BG_map_ram[num]; + u8 * tile = (u8 *)gpu->BG_tile_ram[num]; + u8 * pal = ARM9Mem.ARM9_VMEM + gpu->core * 0x400; +// printf("rot mode\n"); + apply_rot_fun(gpu, num, dst, H,X,Y,PA,PB,PC,PD,LG, rot_tiled_8bit_entry, map, tile, pal); +} + +INLINE void extRotBG2(GPU * gpu, u8 num, u8 * dst, u16 H, s32 X, s32 Y, s16 PA, s16 PB, s16 PC, s16 PD, s16 LG) { struct _BGxCNT bgCnt = gpu->bgCnt[num].bits; - s32 x = X + (s32)PB*(s32)H; - s32 y = Y + (s32)PD*(s32)H; - - s32 dx = PA; - s32 dy = PC; - - s32 auxX; - s32 auxY; - - s16 lg = gpu->BGSize[num][0]; - s16 ht = gpu->BGSize[num][1]; - u16 lgmap = (lg>>3); - - u8 * tile = (u8 *)gpu->BG_tile_ram[num]; - u8 * dst = DST; - u8 * map; - u16 mapinfo, i; - u8 coul; + u8 *map, *tile, *pal; u8 affineModeSelection ; /* see: http://nocash.emubase.de/gbatek.htm#dsvideobgmodescontrol */ affineModeSelection = (bgCnt.Palette_256 << 1) | (bgCnt.CharacBase_Block & 1) ; +// printf("extrot mode %d\n", affineModeSelection); switch(affineModeSelection) { - case 0 : - case 1 : - { - u8 * pal = ARM9Mem.ExtPal[gpu->core][gpu->BGExtPalSlot[num]]; - if(!pal) return; - -#define LOOP(c) \ - for(i = 0; i < LG; ++i) { \ - auxX = x>>8; auxY = y>>8; \ - if(bgCnt.PaletteSet_Wrap) { \ - auxX &= (lg-1); auxY &= (ht-1); \ - } \ - if ((auxX >= 0) && (auxX < lg) && (auxY >= 0) && (auxY < ht)) c \ - dst += 2; x += dx; y += dy; \ - } + case 0 : + case 1 : + // 16 bit bgmap entries map = gpu->BG_map_ram[num]; - LOOP( - { - u16 x1; - u16 y1; - mapinfo = T1ReadWord(map, ((auxX>>3) + (auxY>>3) * lgmap) << 1); - - x1 = (mapinfo & 0x400) ? 7 - (auxX&7) : (auxX&7); - y1 = (mapinfo & 0x800) ? 7 - (auxY&7) : (auxY&7); - coul = tile[(mapinfo&0x3FF)*64 + x1 + (y1<<3)]; - if(coul) - renderline_setFinalColor(gpu,0,num,dst, T1ReadWord(pal, (coul + (mapinfo>>12)*0x100) << 1),i,H); - }) - - } + tile = gpu->BG_tile_ram[num]; + pal = ARM9Mem.ExtPal[gpu->core][gpu->BGExtPalSlot[num]]; + apply_rot_fun(gpu, num, dst, H,X,Y,PA,PB,PC,PD,LG, rot_tiled_16bit_entry, map, tile, pal); return; case 2 : - { - u8 * pal = ARM9Mem.ARM9_VMEM + gpu->core * 0x400; - u8 * map = gpu->BG_bmp_ram[num]; - LOOP( - { - mapinfo = map[auxX + auxY * lg]; - if(mapinfo) - renderline_setFinalColor(gpu,0,num,dst, T1ReadWord(pal, mapinfo << 1),i,H); - }) - } + // 256 colors + map = gpu->BG_bmp_ram[num]; + pal = ARM9Mem.ARM9_VMEM + gpu->core * 0x400; + apply_rot_fun(gpu, num, dst, H,X,Y,PA,PB,PC,PD,LG, rot_256_map, map, NULL, pal); return; - case 3 : /* direct color bitmap */ - { - u8 * map = gpu->BG_bmp_ram[num]; - LOOP( - { - mapinfo = T1ReadWord(map, (auxX + auxY * lg) << 1); - if ((mapinfo) && (mapinfo & 0x8000)) - renderline_setFinalColor(gpu,0,num,dst, mapinfo,i,H); - }) - } + case 3 : + // direct colors / BMP + map = gpu->BG_bmp_ram[num]; + apply_rot_fun(gpu, num, dst, H,X,Y,PA,PB,PC,PD,LG, rot_BMP_map, map, NULL, NULL); return; -#undef LOOP - } + } } void lineText(GPU * gpu, u8 num, u16 l, u8 * DST) @@ -1112,7 +1054,6 @@ INLINE void render_sprite_BMP (GPU * gpu, u16 l, u8 * dst, u16 * src, for(i = 0; i < lg; i++, ++sprX, x+=xdir) { color = src[x]; - //RENDER_COND(color,) // alpha bit = invisible RENDER_COND(color&0x8000) } @@ -1251,82 +1192,96 @@ INLINE void render_sprite_Win (GPU * gpu, u16 l, u8 * src, } } + + +// return val means if the sprite is to be drawn or not +INLINE BOOL compute_sprite_vars(_OAM_ * spriteInfo, u16 l, + size *sprSize, s32 *sprX, s32 *sprY, s32 *x, s32 *y, s32 *lg, int *xdir) { + + *x = 0; + // get sprite location and size + *sprX = (spriteInfo->X<<23)>>23; + *sprY = spriteInfo->Y; + *sprSize = sprSizeTab[spriteInfo->Size][spriteInfo->Shape]; + + *lg = sprSize->x; + + if (*sprY>192) + *sprY = (s32)((s8)(spriteInfo->Y)); + +// FIXME: for rot/scale, a list of entries into the sprite should be maintained, +// that tells us where the first pixel of a screenline starts in the sprite, +// and how a step to the right in a screenline translates within the sprite + + if ((spriteInfo->RotScale == 2) || /* rotscale == 2 => sprite disabled */ + (l<*sprY)||(l>=*sprY+sprSize->y) || /* sprite lines outside of screen */ + (*sprX==256)||(*sprX+sprSize->x<0)) /* sprite pixels outside of line */ + return FALSE; /* not to be drawn */ + + // sprite portion out of the screen (LEFT) + if(*sprX<0) + { + *lg += *sprX; + *x = -(*sprX); + *sprX = 0; + // sprite portion out of the screen (RIGHT) + } else if (*sprX+sprSize->x >= 256) + *lg = 256 - *sprX; + + *y = l - *sprY; /* get the y line within sprite coords */ + + // switch TOP<-->BOTTOM + if (spriteInfo->VFlip) + *y = sprSize->y - *y -1; + + // switch LEFT<-->RIGHT + if (spriteInfo->HFlip) { + *x = sprSize->x - *x -1; + *xdir = -1; + } else { + *xdir = 1; + } + return TRUE; +} + +INLINE void compute_sprite_rotoscale(GPU * gpu, _OAM_ * spriteInfo, + u16 * rotScaleA, u16 * rotScaleB, u16 * rotScaleC, u16 * rotScaleD) { + u16 rotScaleIndex; + // index from 0 to 31 + rotScaleIndex = spriteInfo->RotScalIndex + (spriteInfo->HFlip<<1) + (spriteInfo->VFlip << 2); + /* if we need to do rotscale, gather its parameters */ + /* http://nocash.emubase.de/gbatek.htm#lcdobjoamrotationscalingparameters */ + *rotScaleA = T1ReadWord((u8*)(gpu->oam + rotScaleIndex*0x20 + 0x06),0) ; + *rotScaleB = T1ReadWord((u8*)(gpu->oam + rotScaleIndex*0x20 + 0x0E),0) ; + *rotScaleC = T1ReadWord((u8*)(gpu->oam + rotScaleIndex*0x20 + 0x16),0) ; + *rotScaleD = T1ReadWord((u8*)(gpu->oam + rotScaleIndex*0x20 + 0x1E),0) ; +} + void sprite1D(GPU * gpu, u16 l, u8 * dst, u8 * prioTab) { _OAM_ * spriteInfo = (_OAM_ *)(gpu->oam + (nbShow-1));// + 127; - u8 block = gpu->sprBlock; + u8 block = gpu->sprBoundary; u16 i; for(i = 0; iRotScale & 1) { - /* if we need to do rotscale, gather its parameters */ - /* http://nocash.emubase.de/gbatek.htm#lcdobjoamrotationscalingparameters */ - rotScaleA = T1ReadWord(gpu->oam + spriteInfo->RotScalIndex*0x20 + 0x06,0) ; - rotScaleB = T1ReadWord(gpu->oam + spriteInfo->RotScalIndex*0x20 + 0x0E,0) ; - rotScaleC = T1ReadWord(gpu->oam + spriteInfo->RotScalIndex*0x20 + 0x16,0) ; - rotScaleD = T1ReadWord(gpu->oam + spriteInfo->RotScalIndex*0x20 + 0x1E,0) ; - } ; - - - // get sprite location and size - sprX = (spriteInfo->X<<23)>>23; - sprY = spriteInfo->Y; - sprSize = sprSizeTab[spriteInfo->Size][spriteInfo->Shape]; - - lg = sprSize.x; - - if(sprY>192) - sprY = (s32)((s8)(spriteInfo->Y)); - -/* FIXME: for rot/scale, a list of entries into the sprite should be maintained, that tells us where the first pixel */ -/* of a screenline starts in the sprite, and how a step to the right in a screenline translates within the sprite */ - if( (spriteInfo->RotScale == 2) || /* rotscale == 2 => sprite disabled */ - (l=sprY+sprSize.y) || /* sprite occupies only lines outside the current drawn line */ - (sprX==256) ) /* sprite is outside our line */ - continue; /* for all these problems, continue with the next sprite */ - - // sprite portion out of the screen (LEFT) - if(sprX<0) - { - if(sprX+sprSize.x<0) continue; // fully out of screen - lg += sprX; - x = -sprX; - sprX = 0; - // sprite portion out of the screen (RIGHT) - } else if(sprX+sprSize.x >= 256) - lg = 256 - sprX; - - - y = l - sprY; /* get the y line within sprite coords */ prio = spriteInfo->Priority; + + + if (!compute_sprite_vars(spriteInfo, l, &sprSize, &sprX, &sprY, &x, &y, &lg, &xdir)) + continue; + + if (spriteInfo->RotScale & 1) + compute_sprite_rotoscale(gpu, spriteInfo, + &rotScaleA, &rotScaleB, &rotScaleC, &rotScaleD); - // switch TOP<-->BOTTOM - if (spriteInfo->VFlip) - y = sprSize.y - y -1; - - // switch LEFT<-->RIGHT - if (spriteInfo->HFlip) { - x = sprSize.x -x -1; - xdir = -1; - } else { - xdir = 1; - } - -#if 1 if (spriteInfo->Mode == 2) { if (spriteInfo->Depth) src = gpu->sprMem + (spriteInfo->TileIndex<>3)*sprSize.x*8) + ((y&0x7)*8); @@ -1336,13 +1291,13 @@ void sprite1D(GPU * gpu, u16 l, u8 * dst, u8 * prioTab) spriteInfo->Depth, lg, sprX, x, xdir); continue; } -#endif + if (spriteInfo->Mode == 3) /* sprite is in BMP format */ { - /* sprMemory + sprBlock + 16Bytes per line (8pixels a 2 bytes) */ - src = (gpu->sprMem) + (spriteInfo->TileIndex<<4) + (y<sprBMPBlock); + /* sprMemory + sprBoundary + 16Bytes per line (8pixels a 2 bytes) */ + src = (gpu->sprMem) + (spriteInfo->TileIndex<<4) + (y<sprBMPBoundary); - render_sprite_BMP (gpu, l, dst, src, + render_sprite_BMP (gpu, l, dst, (u16*)src, prioTab, prio, lg, sprX, x, xdir); continue; @@ -1357,7 +1312,7 @@ void sprite1D(GPU * gpu, u16 l, u8 * dst, u8 * prioTab) else pal = ARM9Mem.ARM9_VMEM + 0x200 + gpu->core *0x400; - render_sprite_256 (gpu, l, dst, src, pal, + render_sprite_256 (gpu, l, dst, src, (u16*)pal, prioTab, prio, lg, sprX, x, xdir); continue; @@ -1380,68 +1335,23 @@ void sprite2D(GPU * gpu, u16 l, u8 * dst, u8 * prioTab) for(i = 0; iRotScale & 1) { - /* if we need to do rotscale, gather its parameters */ - /* http://nocash.emubase.de/gbatek.htm#lcdobjoamrotationscalingparameters */ - rotScaleA = T1ReadWord(gpu->oam + spriteInfo->RotScalIndex*0x20 + 0x06,0) ; - rotScaleB = T1ReadWord(gpu->oam + spriteInfo->RotScalIndex*0x20 + 0x0E,0) ; - rotScaleC = T1ReadWord(gpu->oam + spriteInfo->RotScalIndex*0x20 + 0x16,0) ; - rotScaleD = T1ReadWord(gpu->oam + spriteInfo->RotScalIndex*0x20 + 0x1E,0) ; - } ; + s32 sprX, sprY, x, y, lg; + int xdir; + u8 prio, * src, * pal; + u16 i,j; + u16 rotScaleA,rotScaleB,rotScaleC,rotScaleD; + int block; - sprX = (spriteInfo->X<<23)>>23; - sprY = spriteInfo->Y; - sprSize = sprSizeTab[spriteInfo->Size][spriteInfo->Shape]; - - lg = sprSize.x; + prio = spriteInfo->Priority; - if(sprY>192) - sprY = (s32)((s8)(spriteInfo->Y)); - - if( (spriteInfo->RotScale == 2) || - (l=sprY+sprSize.y) || - (sprX==256) ) + if (!compute_sprite_vars(spriteInfo, l, &sprSize, &sprX, &sprY, &x, &y, &lg, &xdir)) continue; - // sprite portion out of the screen (LEFT) - if(sprX<0) - { - if(sprX+sprSize.x<0) continue; // fully out of screen - lg += sprX; - x = -sprX; - sprX = 0; - // sprite portion out of the screen (RIGHT) - } else if(sprX+sprSize.x >= 256) - lg = 256 - sprX; - - y = l - sprY; - prio = spriteInfo->Priority; - - // switch TOP<-->BOTTOM - if (spriteInfo->VFlip) - y = sprSize.y - y -1; - - // switch LEFT<-->RIGHT - if (spriteInfo->HFlip) { - x = sprSize.x -x -1; - xdir = -1; - } else { - xdir = 1; - } -#if 1 + if (spriteInfo->RotScale & 1) + compute_sprite_rotoscale(gpu, spriteInfo, + &rotScaleA, &rotScaleB, &rotScaleC, &rotScaleD); + if (spriteInfo->Mode == 2) { if (spriteInfo->Depth) src = gpu->sprMem + ((spriteInfo->TileIndex)<<5) + ((y>>3)<<10) + ((y&0x7)*8); @@ -1451,12 +1361,15 @@ void sprite2D(GPU * gpu, u16 l, u8 * dst, u8 * prioTab) spriteInfo->Depth, lg, sprX, x, xdir); continue; } -#endif + if (spriteInfo->Mode == 3) /* sprite is in BMP format */ { - src = (gpu->sprMem) + (((spriteInfo->TileIndex&0x3E0) * 64 + (spriteInfo->TileIndex&0x1F) *8 + ( y << 8)) << 1); + if (gpu->dispCnt.bits.OBJ_BMP_2D_dim) // 256*256 + src = (gpu->sprMem) + (((spriteInfo->TileIndex&0x3F0) * 64 + (spriteInfo->TileIndex&0x0F) *8 + ( y << 8)) << 1); + else // 128 * 512 + src = (gpu->sprMem) + (((spriteInfo->TileIndex&0x3E0) * 64 + (spriteInfo->TileIndex&0x1F) *8 + ( y << 8)) << 1); - render_sprite_BMP (gpu, l, dst, src, + render_sprite_BMP (gpu, l, dst, (u16*)src, prioTab, prio, lg, sprX, x, xdir); continue; @@ -1467,7 +1380,7 @@ void sprite2D(GPU * gpu, u16 l, u8 * dst, u8 * prioTab) src = gpu->sprMem + ((spriteInfo->TileIndex)<<5) + ((y>>3)<<10) + ((y&0x7)*8); pal = ARM9Mem.ARM9_VMEM + 0x200 + gpu->core *0x400; - render_sprite_256 (gpu, l, dst, src, pal, + render_sprite_256 (gpu, l, dst, src, (u16*)pal, prioTab, prio, lg, sprX, x, xdir); continue; diff --git a/desmume/src/GPU.h b/desmume/src/GPU.h index 81a4c8d51..52fc2f826 100644 --- a/desmume/src/GPU.h +++ b/desmume/src/GPU.h @@ -58,6 +58,31 @@ extern "C" { #define ADDRESS_STEP_32KB 0x08000 #define ADDRESS_STEP_64kB 0x10000 +struct _TILEENTRY +{ +/* 0*/ unsigned TileNum:10; +/*12*/ unsigned HFlip:1; // HORIZONTAL FLIP (left<-->right) +/*13*/ unsigned VFlip:1; // VERTICAL FLIP (top<-->bottom) +/*14*/ unsigned Palette:4; +}; +typedef union +{ + struct _TILEENTRY bits; + u32 val; +} TILEENTRY; + +struct _ROTOCOORD +{ +/* 0*/ unsigned Fraction:8; +/* 8*/ unsigned Integer:19; +/*27*/ unsigned Sign:1; +/*28*/ unsigned :4; +}; +typedef union +{ + struct _ROTOCOORD bits; + u32 val; +} ROTOCOORD; /* this structure is for display control, @@ -106,6 +131,30 @@ typedef union } DISPCNT; #define BGxENABLED(cnt,num) ((num<8)? ((cnt.val>>8) & num):0) +// source: +// http://nocash.emubase.de/gbatek.htm#dsvideocaptureandmainmemorydisplaymode +struct _DISPCAPCNT +{ +/* 0*/ unsigned BlendFactor_A:5; // 0..16 = Blending Factor for Source A +/* 5*/ unsigned :3; // +/* 8*/ unsigned BlendFactor_B:5; // 0..16 = Blending Factor for Source B +/*13*/ unsigned :3; // +/*16*/ unsigned VRAM_Write_Block:2; // 0..3 = VRAM A..D +/*18*/ unsigned VRAM_Write_Offset:2; // n x 0x08000 +/*20*/ unsigned Capture_Size:2; // 0=128x128, 1=256x64, 2=256x128, 3=256x192 dots +/*22*/ unsigned :2; // +/*24*/ unsigned Source_A:1; // 0=Graphics Screen BG+3D+OBJ, 1=3D Screen +/*25*/ unsigned Source_B:1; // 0=VRAM, 1=Main Memory Display FIFO +/*26*/ unsigned VRAM_Read_Offset:2; // n x 0x08000 +/*28*/ unsigned :1; // +/*29*/ unsigned Capture_Source:2; // 0=Source A, 1=Source B, 2/3=Sources A+B blended +/*31*/ unsigned Capture_Enable:1; // 0=Disable/Ready, 1=Enable/Busy +}; +typedef union +{ + struct _DISPCAPCNT bits; + u32 val; +} DISPCAPCNT; /* @@ -180,6 +229,7 @@ struct _BGxCNT // large : 512x1024 1024x512 - - }; + typedef union { struct _BGxCNT bits; @@ -337,6 +387,7 @@ typedef struct _GPU GPU; struct _GPU { DISPCNT dispCnt; + DISPCAPCNT dispCapCnt; BGxCNT bgCnt[4]; MASTER_BRIGHT masterBright; BOOL LayersEnable[5]; @@ -378,8 +429,8 @@ struct _GPU OAM * oam; u8 * sprMem; - u8 sprBlock; - u8 sprBMPBlock; + u8 sprBoundary; + u8 sprBMPBoundary; u8 sprBMPMode; u32 sprEnable ; @@ -428,8 +479,13 @@ void Screen_DeInit(void); extern MMU_struct MMU; +static INLINE void GPU_set_DISPCAPCNT(GPU * gpu, u32 val) { + gpu->dispCapCnt.val = val; +} + static INLINE void GPU_ligne(Screen * screen, u16 l) { + struct _DISPCAPCNT * capcnt; GPU * gpu = screen->gpu; u8 * dst = GPU_screen + (screen->offset + l) * 512; u8 * mdst = GPU_screen + (MainScreen.offset + l) * 512; @@ -555,6 +611,98 @@ static INLINE void GPU_ligne(Screen * screen, u16 l) } } +// FIXME !!! +/* capture */ +capcnt = &gpu->dispCapCnt.bits; +if (0 & capcnt->Capture_Enable) +{ + u16 * srcA, * srcB, *vram; + u32 c; u8 vram_bank; + COLOR color, colA, colB; + u16 ilast= 128; + if (capcnt->Capture_Size) ilast = 256; + + vram = (u16*)(ARM9Mem.ARM9_ABG + + MMU.vram_mode[capcnt->VRAM_Write_Block] * 0x20000 + + capcnt->VRAM_Write_Offset * 0x08000); + + // I dunno yet how to do for 3D + if (!capcnt->Source_A) + srcA = (u16*)dst; + + if (!capcnt->Source_B) { + vram_bank = gpu->dispCnt.bits.VRAM_Block ; + if (MMU.vram_mode[vram_bank] & 4) { + srcB = (u16*)(ARM9Mem.ARM9_LCD + + (MMU.vram_mode[vram_bank] & 3) * 0x20000 + + capcnt->VRAM_Read_Offset * 0x08000); + } else { + srcB = (u16*)(ARM9Mem.ARM9_ABG + + MMU.vram_mode[vram_bank] * 0x20000 + + capcnt->VRAM_Read_Offset * 0x08000); + } + } + + printf("capture source %d\n",capcnt->Capture_Source); + + switch(capcnt->Capture_Source) { + case 0: // only source A + if (!capcnt->Source_A) { + srcA = (u16*)dst; + for (i=0; iSource_B) { + for (i=0; i>16; i++; + } + } else { + for (i=0; iSource_B) { + for (i=0; iBlendFactor_A) + (colB.bits.field * colB.bits.alpha * capcnt->BlendFactor_B)) / 16; + FORMULA(red) + FORMULA(green) + FORMULA(blue) + vram[i] = color.val; + i++; + colA.val = c >> 16; + colB.val = srcB[i]; + FORMULA(red) + FORMULA(green) + FORMULA(blue) + vram[i] = color.val; + i++; + } + } else { + for (i=0; i