/* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2002 Ben Parnell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" #include "..\..\ntview.h" #include "..\..\fceu.h" #define INESPRIV #include "..\..\cart.h" #include "..\..\ines.h" #include "debugger.h" #include "..\..\palette.h" #include "..\..\ppu.h" HWND hNTView; int NTViewPosX,NTViewPosY; static uint8 palcache[32]; //palette cache //mbg merge 7/19/06 needed to be static //uint8 ntcache0[0x400],ntcache1[0x400],ntcache2[0x400],ntcache3[0x400]; //cache CHR, fixes a refresh problem when right-clicking uint8 *ntable0, *ntable1, *ntable2, *ntable3; //name table bitmap array uint8 *ntablemirr[4]; uint8 ntcache[4][0x400]; //todo: use an array for the above variables too int NTViewScanline=0,NTViewer=0; int NTViewSkip,NTViewRefresh; static int mouse_x,mouse_y; //todo: is static needed here? --mbg 7/19/06 - i think so int redrawtables = 0; int chrchanged = 0; int ntmirroring, oldntmirroring = -1; //0 is horizontal, 1 is vertical, 2 is four screen. int lockmirroring; //int ntmirroring[4]; //these 4 ints are either 0, 1, 2, or 3 and tell where each of the 4 nametables point to //uint8 *ntmirroringpointers[] = {&NTARAM[0x000],&NTARAM[0x400],ExtraNTARAM,ExtraNTARAM+0x400}; int horzscroll, vertscroll; #define NTWIDTH 256 #define NTHEIGHT 240 //#define PATTERNBITWIDTH PATTERNWIDTH*3 #define NTDESTX 10 #define NTDESTY 15 #define ZOOM 1 //#define PALETTEWIDTH 32*4*4 //#define PALETTEHEIGHT 32*2 //#define PALETTEBITWIDTH PALETTEWIDTH*3 //#define PALETTEDESTX 10 //#define PALETTEDESTY 327 void UpdateMirroringButtons(); void ChangeMirroring(); static BITMAPINFO bmInfo; //todo is static needed here so it won't interefere with the pattern table viewer? static HDC pDC,TmpDC0,TmpDC1; static HBITMAP TmpBmp0,TmpBmp1; static HGDIOBJ TmpObj0,TmpObj1; static HDC TmpDC2,TmpDC3; static HBITMAP TmpBmp2,TmpBmp3; static HGDIOBJ TmpObj2,TmpObj3; extern uint32 TempAddr, RefreshAddr; extern uint8 XOffset; int xpos, ypos; int scrolllines = 1; //if you pass this 1 then it will draw no matter what. If you pass it 0 //then it will draw if redrawtables is 1 void NTViewDoBlit(int autorefresh) { if (!hNTView) return; if (NTViewSkip < NTViewRefresh) { NTViewSkip++; return; } NTViewSkip=0; if((redrawtables && !autorefresh) || (autorefresh) || (scrolllines)){ //todo: use switch and use bitblt for because its faster switch(ntmirroring){ case 0: //horizontal BitBlt(pDC,NTDESTX,NTDESTY,NTWIDTH,NTHEIGHT,TmpDC0,0,0,SRCCOPY); BitBlt(pDC,NTDESTX+NTWIDTH,NTDESTY,NTWIDTH,NTHEIGHT,TmpDC0,0,0,SRCCOPY); BitBlt(pDC,NTDESTX,NTDESTY+NTHEIGHT,NTWIDTH,NTHEIGHT,TmpDC1,0,0,SRCCOPY); BitBlt(pDC,NTDESTX+NTWIDTH,NTDESTY+NTHEIGHT,NTWIDTH,NTHEIGHT,TmpDC1,0,0,SRCCOPY); break; case 1: //vertical BitBlt(pDC,NTDESTX,NTDESTY,NTWIDTH,NTHEIGHT,TmpDC0,0,0,SRCCOPY); BitBlt(pDC,NTDESTX+NTWIDTH,NTDESTY,NTWIDTH,NTHEIGHT,TmpDC1,0,0,SRCCOPY); BitBlt(pDC,NTDESTX,NTDESTY+NTHEIGHT,NTWIDTH,NTHEIGHT,TmpDC0,0,0,SRCCOPY); BitBlt(pDC,NTDESTX+NTWIDTH,NTDESTY+NTHEIGHT,NTWIDTH,NTHEIGHT,TmpDC1,0,0,SRCCOPY); break; case 2: //four screen BitBlt(pDC,NTDESTX,NTDESTY,NTWIDTH,NTHEIGHT,TmpDC0,0,0,SRCCOPY); BitBlt(pDC,NTDESTX+NTWIDTH,NTDESTY,NTWIDTH,NTHEIGHT,TmpDC1,0,0,SRCCOPY); BitBlt(pDC,NTDESTX,NTDESTY+NTHEIGHT,NTWIDTH,NTHEIGHT,TmpDC2,0,0,SRCCOPY); BitBlt(pDC,NTDESTX+NTWIDTH,NTDESTY+NTHEIGHT,NTWIDTH,NTHEIGHT,TmpDC3,0,0,SRCCOPY); break; case 3: //single screen, table 0 BitBlt(pDC,NTDESTX,NTDESTY,NTWIDTH,NTHEIGHT,TmpDC0,0,0,SRCCOPY); BitBlt(pDC,NTDESTX+NTWIDTH,NTDESTY,NTWIDTH,NTHEIGHT,TmpDC0,0,0,SRCCOPY); BitBlt(pDC,NTDESTX,NTDESTY+NTHEIGHT,NTWIDTH,NTHEIGHT,TmpDC0,0,0,SRCCOPY); BitBlt(pDC,NTDESTX+NTWIDTH,NTDESTY+NTHEIGHT,NTWIDTH,NTHEIGHT,TmpDC0,0,0,SRCCOPY); break; case 4: //single screen, table 1 BitBlt(pDC,NTDESTX,NTDESTY,NTWIDTH,NTHEIGHT,TmpDC1,0,0,SRCCOPY); BitBlt(pDC,NTDESTX+NTWIDTH,NTDESTY,NTWIDTH,NTHEIGHT,TmpDC1,0,0,SRCCOPY); BitBlt(pDC,NTDESTX,NTDESTY+NTHEIGHT,NTWIDTH,NTHEIGHT,TmpDC1,0,0,SRCCOPY); BitBlt(pDC,NTDESTX+NTWIDTH,NTDESTY+NTHEIGHT,NTWIDTH,NTHEIGHT,TmpDC1,0,0,SRCCOPY); break; case 5: //single screen, table 2 BitBlt(pDC,NTDESTX,NTDESTY,NTWIDTH,NTHEIGHT,TmpDC2,0,0,SRCCOPY); BitBlt(pDC,NTDESTX+NTWIDTH,NTDESTY,NTWIDTH,NTHEIGHT,TmpDC2,0,0,SRCCOPY); BitBlt(pDC,NTDESTX,NTDESTY+NTHEIGHT,NTWIDTH,NTHEIGHT,TmpDC2,0,0,SRCCOPY); BitBlt(pDC,NTDESTX+NTWIDTH,NTDESTY+NTHEIGHT,NTWIDTH,NTHEIGHT,TmpDC2,0,0,SRCCOPY); break; case 6: //single screen, table 3 BitBlt(pDC,NTDESTX,NTDESTY,NTWIDTH,NTHEIGHT,TmpDC3,0,0,SRCCOPY); BitBlt(pDC,NTDESTX+NTWIDTH,NTDESTY,NTWIDTH,NTHEIGHT,TmpDC3,0,0,SRCCOPY); BitBlt(pDC,NTDESTX,NTDESTY+NTHEIGHT,NTWIDTH,NTHEIGHT,TmpDC3,0,0,SRCCOPY); BitBlt(pDC,NTDESTX+NTWIDTH,NTDESTY+NTHEIGHT,NTWIDTH,NTHEIGHT,TmpDC3,0,0,SRCCOPY); break; } /* if(ntmirroring == 0){ //horizontal StretchBlt(pDC,NTDESTX,NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC0,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC0,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX,NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC1,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC1,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); } if(ntmirroring == 1){ //vertical StretchBlt(pDC,NTDESTX,NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC0,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC1,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX,NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC0,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC1,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); } if(ntmirroring == 2){ //four screen StretchBlt(pDC,NTDESTX,NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC0,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC1,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX,NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC2,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC3,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); } if(ntmirroring == 3){ //single screen, table 0 StretchBlt(pDC,NTDESTX,NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC0,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC0,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX,NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC0,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC0,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); } if(ntmirroring == 4){ //single screen, table 1 StretchBlt(pDC,NTDESTX,NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC1,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC1,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX,NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC1,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC1,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); } if(ntmirroring == 5){ //single screen, table 2 StretchBlt(pDC,NTDESTX,NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC2,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC2,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX,NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC2,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC2,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); } if(ntmirroring == 6){ //single screen, table 3 StretchBlt(pDC,NTDESTX,NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC3,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC3,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX,NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC3,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC3,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); } */ redrawtables = 0; } if(scrolllines){ SetROP2(pDC,R2_NOT); //draw vertical line MoveToEx(pDC,NTDESTX+xpos,NTDESTY,NULL); LineTo(pDC,NTDESTX+xpos,NTDESTY+(NTHEIGHT*2)); //draw horizontal line MoveToEx(pDC,NTDESTX,NTDESTY+ypos,NULL); LineTo(pDC,NTDESTX+(NTWIDTH*2),NTDESTY+ypos); SetROP2(pDC,R2_COPYPEN); } //StretchBlt(pDC,NTDESTX,NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC0,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); //StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY,NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC1,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); //StretchBlt(pDC,NTDESTX,NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC2,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); //StretchBlt(pDC,NTDESTX+(NTWIDTH*ZOOM),NTDESTY+(NTHEIGHT*ZOOM),NTWIDTH*ZOOM,NTHEIGHT*ZOOM,TmpDC3,0,NTHEIGHT-1,NTWIDTH,-NTHEIGHT,SRCCOPY); } void UpdateMirroringButtons(){ int i; for(i = 0; i < 7;i++){ if(i != ntmirroring)CheckDlgButton(hNTView, i+1001, BST_UNCHECKED); else CheckDlgButton(hNTView, i+1001, BST_CHECKED); } return; } void ChangeMirroring(){ switch(ntmirroring){ case 0: vnapage[0] = vnapage[1] = &NTARAM[0x000]; vnapage[2] = vnapage[3] = &NTARAM[0x400]; break; case 1: vnapage[0] = vnapage[2] = &NTARAM[0x000]; vnapage[1] = vnapage[3] = &NTARAM[0x400]; break; case 2: vnapage[0] = &NTARAM[0x000]; vnapage[1] = &NTARAM[0x400]; vnapage[2] = ExtraNTARAM; vnapage[3] = ExtraNTARAM+0x400; break; case 3: vnapage[0] = vnapage[1] = vnapage[2] = vnapage[3] = &NTARAM[0x000]; break; case 4: vnapage[0] = vnapage[1] = vnapage[2] = vnapage[3] = &NTARAM[0x400]; break; case 5: vnapage[0] = vnapage[1] = vnapage[2] = vnapage[3] = ExtraNTARAM; break; case 6: vnapage[0] = vnapage[1] = vnapage[2] = vnapage[3] = ExtraNTARAM+0x400; break; } return; } INLINE void DrawChr(uint8 *pbitmap,uint8 *chr,int pal){ int y, x, tmp, index=0, p=0; uint8 chr0, chr1; //uint8 *table = &VPage[0][0]; //use the background table //pbitmap += 3* for (y = 0; y < 8; y++) { //todo: use index for y? chr0 = chr[index]; chr1 = chr[index+8]; tmp=7; for (x = 0; x < 8; x++) { //todo: use tmp for x? p = (chr0>>tmp)&1; p |= ((chr1>>tmp)&1)<<1; p = palcache[p+(pal*4)]; tmp--; *(uint8*)(pbitmap++) = palo[p].b; *(uint8*)(pbitmap++) = palo[p].g; *(uint8*)(pbitmap++) = palo[p].r; } index++; pbitmap += (NTWIDTH*3)-24; } //index+=8; //pbitmap -= (((PALETTEBITWIDTH>>2)<<3)-24); } void DrawNameTable(uint8 *bitmap, uint8 *table, uint8 *tablecache) { int x,y,a, chr, ptable=0, cacheaddr0, cacheaddr1;//index=0; uint8 *pbitmap = bitmap; if(PPU[0]&0x10){ //use the correct pattern table based on this bit ptable=0x1000; } pbitmap = bitmap; for(y = 0;y < 30;y++){ for(x = 0;x < 32;x++){ cacheaddr0 = (y*32)+x; cacheaddr1 = 0x3C0+((y>>2)<<3)+(x>>2); if((tablecache == 0) || (table[cacheaddr0] != tablecache[cacheaddr0]) || (table[cacheaddr1] != tablecache[cacheaddr1])){ redrawtables = 1; a = (table[0x3C0+((y>>2)<<3)+(x>>2)] & (3<<(((y&2)<<1)+(x&2)))) >> (((y&2)<<1)+(x&2)); //the commented out code below is all equilivent to the single line above. //tmpx = x>>2; //tmpy = y>>2; //a = 0x3C0+(tmpy*8)+tmpx; //if((((x>>1)&1) == 0) && (((y>>1)&1) == 0)) a = table[a]&0x3; //if((((x>>1)&1) == 1) && (((y>>1)&1) == 0)) a = (table[a]&0xC)>>2; //if((((x>>1)&1) == 0) && (((y>>1)&1) == 1)) a = (table[a]&0x30)>>4; //if((((x>>1)&1) == 1) && (((y>>1)&1) == 1)) a = (table[a]&0xC0)>>6; chr = table[y*32+x]*16; DrawChr(pbitmap,&VPage[(ptable+chr)>>10][ptable+chr],a); if(tablecache != 0){ tablecache[cacheaddr0] = table[cacheaddr0]; //tablecache[cacheaddr1] = table[cacheaddr1]; } } pbitmap += (8*3); } pbitmap += 7*((NTWIDTH*3)); } if((tablecache != 0) && (redrawtables)){ //this copies the attribute tables to the cache if needed memcpy(tablecache+0x3c0,table+0x3c0,0x40); } } void UpdateNTView(int drawall) { //uint8 *pbitmap = ppuv_palette; if (!hNTView) return; xpos = ((RefreshAddr & 0x400) >> 2) | ((RefreshAddr & 0x1F) << 3) | XOffset; ypos = ((RefreshAddr & 0x3E0) >> 2) | ((RefreshAddr & 0x7000) >> 12); if(RefreshAddr & 0x800) ypos += 240; //char str[50]; //sprintf(str,"%d,%d,%d",horzscroll,vertscroll,ntmirroring); //sprintf(str,"%08X %08X",TempAddr, RefreshAddr); //SetDlgItemText(hNTView, 103, str); if (NTViewSkip < NTViewRefresh) return; if(chrchanged) drawall = 1; //update palette only if required if (memcmp(palcache,PALRAM,32) != 0) { memcpy(palcache,PALRAM,32); drawall = 1; //palette has changed, so redraw all } ntmirroring = -1; if(vnapage[0] == vnapage[1])ntmirroring = 0; if(vnapage[0] == vnapage[2])ntmirroring = 1; if((vnapage[0] != vnapage[1]) && (vnapage[0] != vnapage[2]))ntmirroring = 2; if((vnapage[0] == vnapage[1]) && (vnapage[1] == vnapage[2]) && (vnapage[2] == vnapage[3])){ if(vnapage[0] == &NTARAM[0x000])ntmirroring = 3; if(vnapage[0] == &NTARAM[0x400])ntmirroring = 4; if(vnapage[0] == ExtraNTARAM)ntmirroring = 5; if(vnapage[0] == ExtraNTARAM+0x400)ntmirroring = 6; } if(oldntmirroring != ntmirroring){ UpdateMirroringButtons(); oldntmirroring = ntmirroring; } if(drawall){ DrawNameTable(ntable0,&NTARAM[0x000],0); DrawNameTable(ntable1,&NTARAM[0x400],0); DrawNameTable(ntable2,ExtraNTARAM,0); DrawNameTable(ntable3,ExtraNTARAM+0x400,0); } else { if((ntmirroring == 0) || (ntmirroring == 1) || (ntmirroring == 3)) DrawNameTable(ntable0,&NTARAM[0x000],ntcache[0]); if((ntmirroring == 0) || (ntmirroring == 1) || (ntmirroring == 4)) DrawNameTable(ntable1,&NTARAM[0x400],ntcache[1]); if(ntmirroring == 2){ DrawNameTable(ntable2,ExtraNTARAM,ntcache[2]); DrawNameTable(ntable3,ExtraNTARAM+0x400,ntcache[3]); } } chrchanged = 0; return; } void KillNTView() { //GDI cleanup DeleteObject(TmpBmp0); SelectObject(TmpDC0,TmpObj0); DeleteDC(TmpDC0); DeleteObject(TmpBmp1); SelectObject(TmpDC1,TmpObj1); DeleteDC(TmpDC1); DeleteObject(TmpBmp2); SelectObject(TmpDC2,TmpObj2); DeleteDC(TmpDC2); DeleteObject(TmpBmp3); SelectObject(TmpDC3,TmpObj3); DeleteDC(TmpDC3); ReleaseDC(hNTView,pDC); DeleteObject (SelectObject (pDC, GetStockObject (BLACK_PEN))) ; DestroyWindow(hNTView); hNTView=NULL; NTViewer=0; NTViewSkip=0; } extern void StopSound(void); BOOL CALLBACK NTViewCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { RECT wrect; char str[50]; int TileID, TileX, TileY, NameTable, PPUAddress; switch(uMsg) { case WM_INITDIALOG: //SetWindowPos(hwndDlg,0,PPUViewPosX,PPUViewPosY,0,0,SWP_NOSIZE|SWP_NOZORDER|SWP_NOOWNERZORDER); //prepare the bitmap attributes //pattern tables memset(&bmInfo.bmiHeader,0,sizeof(BITMAPINFOHEADER)); bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmInfo.bmiHeader.biWidth = NTWIDTH; bmInfo.bmiHeader.biHeight = -NTHEIGHT; bmInfo.bmiHeader.biPlanes = 1; bmInfo.bmiHeader.biBitCount = 24; //create memory dcs pDC = GetDC(hwndDlg); // GetDC(GetDlgItem(hwndDlg,101)); TmpDC0 = CreateCompatibleDC(pDC); //name table 0 TmpDC1 = CreateCompatibleDC(pDC); //name table 1 TmpDC2 = CreateCompatibleDC(pDC); //name table 2 TmpDC3 = CreateCompatibleDC(pDC); //name table 3 //TmpDC2 = CreateCompatibleDC(pDC); //palettes //create bitmaps and select them into the memory dc's TmpBmp0 = CreateDIBSection(pDC,&bmInfo,DIB_RGB_COLORS,(void**)&ntable0,0,0); TmpObj0 = SelectObject(TmpDC0,TmpBmp0); TmpBmp1 = CreateDIBSection(pDC,&bmInfo,DIB_RGB_COLORS,(void**)&ntable1,0,0); TmpObj1 = SelectObject(TmpDC1,TmpBmp1); TmpBmp2 = CreateDIBSection(pDC,&bmInfo,DIB_RGB_COLORS,(void**)&ntable2,0,0); TmpObj2 = SelectObject(TmpDC2,TmpBmp2); TmpBmp3 = CreateDIBSection(pDC,&bmInfo,DIB_RGB_COLORS,(void**)&ntable3,0,0); TmpObj3 = SelectObject(TmpDC3,TmpBmp3); //Refresh Trackbar SendDlgItemMessage(hwndDlg,201,TBM_SETRANGE,0,(LPARAM)MAKELONG(0,25)); SendDlgItemMessage(hwndDlg,201,TBM_SETPOS,1,NTViewRefresh); //Set Text Limit SendDlgItemMessage(hwndDlg,102,EM_SETLIMITTEXT,3,0); //force redraw the first time the PPU Viewer is opened NTViewSkip=100; SelectObject (pDC, CreatePen (PS_SOLID, 2, RGB (255, 255, 255))) ; CheckDlgButton(hwndDlg, 1008, BST_CHECKED); //clear cache //memset(palcache,0,32); //memset(ntcache0,0,0x400); //memset(ntcache1,0,0x400); //memset(ntcache2,0,0x400); //memset(ntcache3,0,0x400); NTViewer=1; break; case WM_PAINT: NTViewDoBlit(1); break; case WM_CLOSE: case WM_QUIT: KillNTView(); break; case WM_MOVING: StopSound(); break; case WM_MOVE: GetWindowRect(hwndDlg,&wrect); //NTViewPosX = wrect.left; //todo: is this needed? //NTViewPosY = wrect.top; break; case WM_RBUTTONDBLCLK: case WM_RBUTTONDOWN: mouse_x = GET_X_LPARAM(lParam); mouse_y = GET_Y_LPARAM(lParam); /*if (((mouse_x >= PATTERNDESTX) && (mouse_x < (PATTERNDESTX+(PATTERNWIDTH*ZOOM)))) && (mouse_y >= PATTERNDESTY) && (mouse_y < (PATTERNDESTY+(PATTERNHEIGHT*ZOOM)))) { if (pindex0 == 7) pindex0 = 0; else pindex0++; } else if (((mouse_x >= PATTERNDESTX+(PATTERNWIDTH*ZOOM)+1) && (mouse_x < (PATTERNDESTX+(PATTERNWIDTH*ZOOM)*2+1))) && (mouse_y >= PATTERNDESTY) && (mouse_y < (PATTERNDESTY+(PATTERNHEIGHT*ZOOM)))) { if (pindex1 == 7) pindex1 = 0; else pindex1++; } UpdatePPUView(0); PPUViewDoBlit();*/ break; case WM_MOUSEMOVE: mouse_x = GET_X_LPARAM(lParam); mouse_y = GET_Y_LPARAM(lParam); if((mouse_x > NTDESTX) && (mouse_x < NTDESTX+(NTWIDTH*2)) && (mouse_y > NTDESTY) && (mouse_y < NTDESTY+(NTHEIGHT*2))){ TileX = (mouse_x-NTDESTX)/8; TileY = (mouse_y-NTDESTY)/8; sprintf(str,"X / Y: %0d / %0d",TileX,TileY); SetDlgItemText(hwndDlg,104,str); NameTable = (TileX/32)+((TileY/30)*2); PPUAddress = 0x2000+(NameTable*0x400)+((TileY%30)*32)+(TileX%32); sprintf(str,"PPU Address: %04X",PPUAddress); SetDlgItemText(hwndDlg,105,str); TileID = vnapage[(PPUAddress>>10)&0x3][PPUAddress&0x3FF]; sprintf(str,"Tile ID: %02X",TileID); SetDlgItemText(hwndDlg,103,str); } /* if (((mouse_x >= PATTERNDESTX) && (mouse_x < (PATTERNDESTX+(PATTERNWIDTH*ZOOM)))) && (mouse_y >= PATTERNDESTY) && (mouse_y < (PATTERNDESTY+(PATTERNHEIGHT*ZOOM)))) { mouse_x = (mouse_x-PATTERNDESTX)/(8*ZOOM); mouse_y = (mouse_y-PATTERNDESTY)/(8*ZOOM); sprintf(str,"Tile: $%X%X",mouse_y,mouse_x); SetDlgItemText(hwndDlg,103,str); SetDlgItemText(hwndDlg,104,"Tile:"); SetDlgItemText(hwndDlg,105,"Palettes"); } else if (((mouse_x >= PATTERNDESTX+(PATTERNWIDTH*ZOOM)+1) && (mouse_x < (PATTERNDESTX+(PATTERNWIDTH*ZOOM)*2+1))) && (mouse_y >= PATTERNDESTY) && (mouse_y < (PATTERNDESTY+(PATTERNHEIGHT*ZOOM)))) { mouse_x = (mouse_x-(PATTERNDESTX+(PATTERNWIDTH*ZOOM)+1))/(8*ZOOM); mouse_y = (mouse_y-PATTERNDESTY)/(8*ZOOM); sprintf(str,"Tile: $%X%X",mouse_y,mouse_x); SetDlgItemText(hwndDlg,104,str); SetDlgItemText(hwndDlg,103,"Tile:"); SetDlgItemText(hwndDlg,105,"Palettes"); } else if (((mouse_x >= PALETTEDESTX) && (mouse_x < (PALETTEDESTX+PALETTEWIDTH))) && (mouse_y >= PALETTEDESTY) && (mouse_y < (PALETTEDESTY+PALETTEHEIGHT))) { mouse_x = (mouse_x-PALETTEDESTX)/32; mouse_y = (mouse_y-PALETTEDESTY)/32; sprintf(str,"Palette: $%02X",palcache[(mouse_y<<4)|mouse_x]); SetDlgItemText(hwndDlg,103,"Tile:"); SetDlgItemText(hwndDlg,104,"Tile:"); SetDlgItemText(hwndDlg,105,str); } else { SetDlgItemText(hwndDlg,103,"Tile:"); SetDlgItemText(hwndDlg,104,"Tile:"); SetDlgItemText(hwndDlg,105,"Palettes"); } */ break; case WM_NCACTIVATE: sprintf(str,"%d",NTViewScanline); SetDlgItemText(hwndDlg,102,str); break; case WM_COMMAND: switch(HIWORD(wParam)) { case EN_UPDATE: GetDlgItemText(hwndDlg,102,str,4); sscanf(str,"%d",&NTViewScanline); if (NTViewScanline > 239) NTViewScanline = 239; chrchanged = 1; break; case BN_CLICKED: switch(LOWORD(wParam)) { case 1001 : case 1002 : case 1003 : case 1004 : case 1005 : case 1006 : case 1007 : oldntmirroring = ntmirroring = LOWORD(wParam)-1001; ChangeMirroring(); break; case 1008 : scrolllines ^= 1; chrchanged = 1; break; } break; } break; case WM_HSCROLL: if (lParam) { //refresh trackbar NTViewRefresh = SendDlgItemMessage(hwndDlg,201,TBM_GETPOS,0,0); } break; } return FALSE; } void DoNTView() { if (!GI) { FCEUD_PrintError("You must have a game loaded before you can use the Name Table Viewer."); return; } if (GI->type==GIT_NSF) { FCEUD_PrintError("Sorry, you can't use the Name Table Viewer with NSFs."); return; } if (!hNTView) hNTView = CreateDialog(fceu_hInstance,"NTVIEW",NULL,NTViewCallB); if (hNTView) { SetWindowPos(hNTView,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER); UpdateNTView(1); NTViewDoBlit(1); } }