📄 gbagpu.cpp
字号:
rotScaleParam = (attr1 >> 9) & 0x1F; dx = (s16)OAMh[(rotScaleParam * 4 * 4) + 3]; dmx = (s16)OAMh[(rotScaleParam * 4 * 4) + 7]; dy = (s16)OAMh[(rotScaleParam * 4 * 4) + 11]; dmy = (s16)OAMh[(rotScaleParam * 4 * 4) + 15]; cx = rwidth / 2; cy = rheight / 2; baseSprite = attr2 & 0x3FF; if (dispcnt&0x0040) // 1 dimensional pitch = (width / 8) * scale; else // 2 dimensional pitch = 0x20; rx = (s16)((dmx * (spritey - cy)) - (cx * dx) + (width << 7)); ry = (s16)((dmy * (spritey - cy)) - (cx * dy) + (height << 7)); // Draw a rot/scale sprite if (attr0&0x2000) { //if(baseSprite && spritey>=0 && spritey<height) //printf("GPU: Line #%d: Sprite #%d: %dx%d at %d,%d, rotating, 8-bit\n",curline,oamNum,width,height,x,y); // 256 colors for (i = x; i < x + rwidth; i++) { tx = rx >> 8; ty = ry >> 8; if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height) { curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 8) + (tx & 7); b = VRAMb[0x10000 + curIdx]; if(b) COLSHIFT(buf+(i&0x1ff)*4, PALh[b+256]); } rx += dx; ry += dy; } } else { // 16 colors //if(baseSprite && spritey>=0 && spritey<height) //printf("GPU: Line #%d: Sprite #%d: %dx%d at %d,%d, rotating, 4-bit\n",curline,oamNum,width,height,x,y); palIdx = ((attr2 >> 8) & 0xF0); for (i = x; i < x + rwidth; i++) { tx = rx >> 8; ty = ry >> 8; if ((i & 0x1ff) < 240 && tx >= 0 && tx < width && ty >= 0 && ty < height) { curIdx = (baseSprite + ((ty / 8) * pitch) + ((tx / 8) * scale)) * 32 + ((ty & 7) * 4) + ((tx & 7) / 2); b = VRAMb[0x10000 + curIdx]; if (tx & 1) b>>=4; b&=15; if(b) COLSHIFT(buf+(i&0x1ff)*4, PALh[palIdx+b+256]); } rx += dx; ry += dy; } } } } while(oamNum);}// NOTE: Each renderer draws the backgrounds in reverse priority order,// rendering the sprites on each priority level after the background.// Mode 0: 4 tiled BGsvoid gbaGPU::lineM0(u8 *buf){ u16 dispcnt=REG(DISPCNT); for(int pri=3;pri>=0;pri--) { if(ForceBG[3]!=2) if(dispcnt&0x0800 || ForceBG[3]) if((REG(BG3CNT)&3)==pri) scanTile(buf,3); if(ForceBG[2]!=2) if(dispcnt&0x0400 || ForceBG[2]) if((REG(BG2CNT)&3)==pri) scanTile(buf,2); if(ForceBG[1]!=2) if(dispcnt&0x0200 || ForceBG[1]) if((REG(BG1CNT)&3)==pri) scanTile(buf,1); if(ForceBG[0]!=2) if(dispcnt&0x0100 || ForceBG[0]) if((REG(BG0CNT)&3)==pri) scanTile(buf,0); sprites(buf,pri); }}// Mode 1: Two tiled and 1 rot BGvoid gbaGPU::lineM1(u8 *buf){ u16 dispcnt=REG(DISPCNT); for(int pri=3;pri>=0;pri--) { if(ForceBG[3]!=2) if(dispcnt&0x0400 || ForceBG[2]) if((REG(BG2CNT)&3)==pri) scanRot(buf,2); if(ForceBG[2]!=2) if(dispcnt&0x0200 || ForceBG[1]) if((REG(BG1CNT)&3)==pri) scanTile(buf,1); if(ForceBG[1]!=2) if(dispcnt&0x0100 || ForceBG[0]) if((REG(BG0CNT)&3)==pri) scanTile(buf,0); sprites(buf,pri); }}// Mode 2: 2 rot backgroundsvoid gbaGPU::lineM2(u8 *buf){ u16 dispcnt=REG(DISPCNT); for(int pri=3;pri>=0;pri--) { if(ForceBG[3]!=2) if(dispcnt&0x0800 || ForceBG[3]) if((REG(BG3CNT)&3)==pri) scanRot(buf,3); if(ForceBG[2]!=2) if(dispcnt&0x0400 || ForceBG[2]) if((REG(BG2CNT)&3)==pri) scanRot(buf,2); sprites(buf,pri); }}// Mode 3: Flat (rotatable) 16-bit framebuffervoid gbaGPU::lineM3(u8 *buf){ u16 dispcnt=REG(DISPCNT), bg2cnt=REG(BG2CNT), i; int pri; u32 x,y,ax,ay; s16 dx,dy; u16 mosx,mospx,mosy; for(pri=3;pri>(bg2cnt&3);pri--) sprites(buf,pri); if(ForceBG[2]!=2 && (dispcnt&0x0400 || ForceBG[2]==1)) { x=BGX[0]; y=BGY[0]; if(bg2cnt&0x0040) { mosx=(REG(MOSAIC)&0x000F); mosy=((REG(MOSAIC)&0x00F0)>>4); mospx=mosx; if(!curline) mospy[2]=mosy; mospy[2]++; if(mospy[2]<=mosy) y-=mospy[2]*256; else mospy[2]=0; } else { mospx=0; mosx=0; } dx=(signed)REG(BG2PA); dy=(signed)REG(BG2PC); for(i=0;i<240;i++) { ax=x>>8; ay=y>>8; if (ax >= 0 && ax < 240 && ay >= 0 && ay < 160) { if(mospx>=mosx) COLSHIFT(buf+i*4, VRAMh[ay*240+ax]); } mospx+=(dx>>8); if(mospx>mosx) mospx=0; x+=dx; y+=dy; } } for(pri=(bg2cnt&3);pri>=0;pri--) sprites(buf,pri);}// Mode 4: 2 paletted framebuffers, switchable on BG2CNT bit 4void gbaGPU::lineM4(u8 *buf){ u16 dispcnt=REG(DISPCNT), bg2cnt=REG(BG2CNT), i; int pri; u32 x,y,ax,ay; s16 dx,dy; u8 b=0; u16 mosx,mospx,mosy; u16 baseIdx=(bg2cnt&0x0010)?0xA000:0; for(pri=3;pri>(bg2cnt&3);pri--) sprites(buf,pri); if(ForceBG[2]!=2 && (dispcnt&0x0400 || ForceBG[2]==1)) { x=BGX[0]; y=BGY[0]; if(bg2cnt&0x0040) { mosx=(REG(MOSAIC)&0x000F); mosy=((REG(MOSAIC)&0x00F0)>>4); mospx=mosx; if(!curline) mospy[2]=mosy; mospy[2]++; if(mospy[2]<=mosy) y-=mospy[2]*256; else mospy[2]=0; } else { mospx=0; mosx=0; } dx=(signed)REG(BG2PA); dy=(signed)REG(BG2PC); for(i=0;i<240;i++) { ax=x>>8; ay=y>>8; if (ax >= 0 && ax < 240 && ay >= 0 && ay < 160) { if(mospx>=mosx) b=VRAMb[baseIdx+ay*240+ax]; if(b) COLSHIFT(buf+i*4, PALh[b]); } mospx+=(dx>>8); if(mospx>mosx) mospx=0; x+=dx; y+=dy; } } for(pri=(bg2cnt&3);pri>=0;pri--) sprites(buf,pri);}// Mode 5: 2 reduced-size framebuffers, switchable on BG2CNT b4void gbaGPU::lineM5(u8 *buf){ u16 dispcnt=REG(DISPCNT), bg2cnt=REG(BG2CNT), i; int pri; u32 x,y,ax,ay; s16 dx,dy; u16 mosx,mospx,mosy; u16 baseIdx=(bg2cnt&0x0010)?(160*128):0; for(pri=3;pri>(bg2cnt&3);pri--) sprites(buf,pri); if(ForceBG[2]!=2 && (dispcnt&0x0400 || ForceBG[2]==1)) { x=BGX[0]; y=BGY[0]; if(bg2cnt&0x0040) { mosx=(REG(MOSAIC)&0x000F); mosy=((REG(MOSAIC)&0x00F0)>>4); mospx=mosx; if(!curline) mospy[2]=mosy; mospy[2]++; if(mospy[2]<=mosy) y-=mospy[2]*256; else mospy[2]=0; } else { mospx=0; mosx=0; } dx=(signed)REG(BG2PA); dy=(signed)REG(BG2PC); for(i=0;i<240;i++) { ax=x>>8; ay=y>>8; if (ax >= 0 && ax < 160 && ay >= 0 && ay < 128) { if(mospx>=mosx) COLSHIFT(buf+i*4, VRAMh[baseIdx+ay*160+ax]); } mospx+=(dx>>8); if(mospx>mosx) mospx=0; x+=dx; y+=dy; } } for(pri=(bg2cnt&3);pri>=0;pri--) sprites(buf,pri);}// Null renderer: Should never have to draw this.void gbaGPU::lineMNULL(u8 *buf){ Logger::log(pluginName) << "How'd we get to lineMNULL?";}// Tell the GPU where it'll be rendering tovoid gbaGPU::setDisplay(u8 *buf){ dispbuffer=buf;}// Render a scanline (wrapper for mode-specific renderers)void gbaGPU::line(){ u16 dispcnt = REG(DISPCNT); u8 *buffer = dispbuffer; if(curline >= 0 && curline <= 160) { buffer += (curline*240*4); if(dispcnt&0x0080) // Blank screen { for(int i=0; i<240; ++i) COLSHIFT(buffer+i*4, 0x00FFFFFF); } else // First draw the backdrop, then the line { for(int i=0; i<240; ++i) COLSHIFT(buffer+i*4, PALh[0]); lineM[dispcnt&7](buffer); } } // The line's done, so hblank begins HBLstart();}// Beginning of hblank: Set hbl bit, fire interruptvoid gbaGPU::HBLstart(){ reg[REG_DISPSTAT].b[0] |= 2; if(reg[REG_DISPSTAT].b[0] & 16) { if((MMU->rdH(0x04000200) & 2) && MMU->rdH(0x04000208)) { MMU->wrH(0x04000202, MMU->rdH(0x04000202)&~2); CPU->interrupt(CPU_INTERRUPT_NORMAL); } } MMU->event(MMU_EVENT_IMMEDIATE, NULL); // Tell the GUI to stop hblank in 272 cycles GUI->eventPush(272, EVENT_HBLANK_END, (vfptr)hblankend, this);}// Finish hblankvoid gbaGPU::HBLend(){ curline++; // If that end of hblank took us to line 160, we've come to the vblank. // Fire that off to the CPU if(curline==160) { reg[REG_DISPSTAT].b[0] |= 1; if(reg[REG_DISPSTAT].b[0] & 8) { if((MMU->rdH(0x04000200) & 1) && MMU->rdH(0x04000208)) { MMU->wrH(0x04000202, MMU->rdH(0x04000202)&~1); CPU->interrupt(CPU_INTERRUPT_NORMAL); } } } if(curline>227) curline = 0; // Update line counter. If we hit a requested vcount, fire // an interrupt. reg[REG_VCOUNT].b[0] = curline; if(curline == reg[REG_DISPSTAT].b[1]) { reg[REG_DISPSTAT].b[0] |= 4; if(reg[REG_DISPSTAT].b[0] & 32) { if((MMU->rdH(0x04000200) & 4) && MMU->rdH(0x04000208)) { MMU->wrH(0x04000202, MMU->rdH(0x04000202)&~4); CPU->interrupt(CPU_INTERRUPT_NORMAL); } } } else reg[REG_DISPSTAT].b[0] &= ~4; REG(DISPSTAT)&=(~2); // Update the background rotation characteristics. If we're at // the top of the screen, reload them. BGX[0]+=(s16)REG(BG2PB); BGY[0]+=(s16)REG(BG2PD); BGX[1]+=(s16)REG(BG3PB); BGY[1]+=(s16)REG(BG3PD); switch(curline) { case 0: REG(DISPSTAT)&=(~1); BGX[0]=REG(BG2XL)+(REG(BG2XH)<<16); BGX[1]=REG(BG3XL)+(REG(BG3XH)<<16); BGY[0]=REG(BG2YL)+(REG(BG2YH)<<16); BGY[1]=REG(BG3YL)+(REG(BG3YH)<<16); break; case 160: REG(DISPSTAT)|=1; break; } MMU->event(MMU_EVENT_IMMEDIATE, NULL); // Tell the GUI to draw a line in 960 cycles' time. GUI->eventPush(960, EVENT_HBLANK_START, (vfptr)drawline, this);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -