diff -NaHudr b/src/drivers/pc/Makefile.am.inc a/src/drivers/pc/Makefile.am.inc --- b/src/drivers/pc/Makefile.am.inc 2004-10-10 01:43:13.000000000 +0300 +++ a/src/drivers/pc/Makefile.am.inc 2005-04-07 15:00:37.000000000 +0300 @@ -1,4 +1,4 @@ -fceud_SOURCES = drivers/pc/nesvideos-piece.cc drivers/pc/input.c drivers/pc/main.c drivers/pc/sdl.c drivers/pc/sdl-joystick.c drivers/pc/sdl-sound.c drivers/pc/sdl-throttle.c drivers/pc/sdl-video.c drivers/pc/unix-netplay.c +fceud_SOURCES = drivers/pc/input.c drivers/pc/main.c drivers/pc/sdl.c drivers/pc/sdl-joystick.c drivers/pc/sdl-sound.c drivers/pc/sdl-throttle.c drivers/pc/sdl-video.c drivers/pc/unix-netplay.c drivers/pc/tiletracker.cc if OPENGL TMP_OGL = drivers/pc/sdl-opengl.c diff -NaHudr b/src/drivers/pc/doubledeque.hh a/src/drivers/pc/doubledeque.hh --- b/src/drivers/pc/doubledeque.hh 1970-01-01 02:00:00.000000000 +0200 +++ a/src/drivers/pc/doubledeque.hh 2005-04-07 18:45:40.000000000 +0300 @@ -0,0 +1,203 @@ +//************************************************************************ +// DoubleDeque +//************************************************************************ + + +#ifndef DOUBLEDEQUE_HH +#define DOUBLEDEQUE_HH + +#include + +template +class DoubleDeque +{ + public: + class Row; + + ItemType& at(int rowIndex, int colIndex); + + const Row& getRow(int rowIndex) const; + + void clear(); + + + DoubleDeque() {} + + +//----------------------------------------------------------------------- + private: + template + class AutoDeque; + + AutoDeque rows; + + // Disable copying and assignment: + DoubleDeque(const DoubleDeque&); + const DoubleDeque& operator=(const DoubleDeque&); +}; + + +template +class DoubleDeque::Row +{ + public: + ItemType& at(int colIndex); + const ItemType& at(int colIndex) const; + + + private: + AutoDeque data; +}; + + + +//======================================================================= +//======================================================================= +// Implementations +//======================================================================= +//======================================================================= + +template +template +class DoubleDeque::AutoDeque +{ + static const int BLOCK_SIZE = 256; + + std::vector dataBlocks; + int currentMinIndex, currentMaxIndex; + int firstItemAbsoluteIndex; + + T defaultValue; + + int getBlockIndexOf(int index) + { + if(index >= 0) return index/BLOCK_SIZE; + return (index-(BLOCK_SIZE-1))/BLOCK_SIZE; + } + + + public: + AutoDeque(): + currentMinIndex(0), currentMaxIndex(-1), firstItemAbsoluteIndex(0) + {} + + ~AutoDeque() + { + clear(); + } + + T& at(int index) + { + if(dataBlocks.empty()) + { + dataBlocks.push_back(new T[BLOCK_SIZE]); + currentMinIndex = index; + currentMaxIndex = index; + firstItemAbsoluteIndex = + index - BLOCK_SIZE*getBlockIndexOf(index); + } + + else if(index < currentMinIndex) + { + const int currentMinIndexBlock = getBlockIndexOf(currentMinIndex); + const int newMinIndexBlock = getBlockIndexOf(index); + if(newMinIndexBlock < currentMinIndexBlock) + { + const unsigned newBlocksAmount = + currentMinIndexBlock - newMinIndexBlock; + + // We assume this happens rarely so its speed doesn't + // really matter: + dataBlocks.insert(dataBlocks.begin(), newBlocksAmount, 0); + + for(unsigned i = 0; i < newBlocksAmount; ++i) + { + dataBlocks[i] = new T[BLOCK_SIZE]; + } + } + + currentMinIndex = index; + firstItemAbsoluteIndex = index - BLOCK_SIZE*newMinIndexBlock; + } + + else if(index > currentMaxIndex) + { + const int currentMaxIndexBlock = getBlockIndexOf(currentMaxIndex); + const int newMaxIndexBlock = getBlockIndexOf(index); + if(newMaxIndexBlock > currentMaxIndexBlock) + { + const unsigned newBlocksAmount = + newMaxIndexBlock - currentMaxIndexBlock; + + for(unsigned i = 0; i < newBlocksAmount; ++i) + { + dataBlocks.push_back(new T[BLOCK_SIZE]); + } + } + + currentMaxIndex = index; + } + + const int i = index - currentMinIndex + firstItemAbsoluteIndex; + return dataBlocks[i/BLOCK_SIZE][i%BLOCK_SIZE]; + } + + const T& at(int index) const + { + if(index < currentMinIndex || index > currentMaxIndex) + return defaultValue; + + const int i = index - currentMinIndex + firstItemAbsoluteIndex; + return dataBlocks[i/BLOCK_SIZE][i%BLOCK_SIZE]; + } + + void clear() + { + currentMinIndex = 0; currentMaxIndex = -1; + for(unsigned i = 0; i < dataBlocks.size(); ++i) + delete[] dataBlocks[i]; + dataBlocks.clear(); + } + + + private: + // Disable copying and assignment: + AutoDeque(const AutoDeque&); + const AutoDeque& operator=(const AutoDeque&); +}; + + +template +ItemType& DoubleDeque::Row::at(int colIndex) +{ + return data.at(colIndex); +} + +template +const ItemType& DoubleDeque::Row::at(int colIndex) const +{ + return data.at(colIndex); +} + +template +ItemType& DoubleDeque::at(int rowIndex, int colIndex) +{ + return rows.at(rowIndex).at(colIndex); +} + +template +const typename DoubleDeque::Row& +DoubleDeque::getRow(int rowIndex) const +{ + return rows.at(rowIndex); +} + +template +void DoubleDeque::clear() +{ + rows.clear(); +} + + + +#endif diff -NaHudr b/src/drivers/pc/input.c a/src/drivers/pc/input.c --- b/src/drivers/pc/input.c 2004-10-10 02:11:50.000000000 +0300 +++ a/src/drivers/pc/input.c 2005-04-07 20:50:54.000000000 +0300 @@ -81,7 +81,7 @@ static void UpdateTopRider(void); static uint32 JSreturn; -int NoWaiting=0; +int NoWaiting=1; #ifndef EXTGUI static void DoCheatSeq(void) @@ -127,9 +127,16 @@ static int cidisabled=0; +static const char* WillLoadMovie = NULL; static void KeyboardCommands(void) { - int is_shift, is_alt; + int is_shift, is_alt, is_ctrl; + + if(WillLoadMovie) + { + FCEUI_LoadMovie(WillLoadMovie, 1); + WillLoadMovie = NULL; + } keys=GetKeyboard(); @@ -148,15 +155,18 @@ is_shift = KEY(LEFTSHIFT) | KEY(RIGHTSHIFT); is_alt = KEY(LEFTALT) | KEY(RIGHTALT); + is_ctrl = KEY(LEFTCONTROL) | KEY(RIGHTCONTROL); if(keyonly(F4)) { if(is_shift) FCEUI_SetRenderDisable(-1, 2); else FCEUI_SetRenderDisable(2, -1); } +#if 0 #ifdef SDL if(keyonly(ENTER) && is_alt) ToggleFS(); #endif +#endif NoWaiting&=~1; if(KEY(GRAVE)) @@ -175,56 +185,69 @@ if(keyonly(F2)) DoCheatSeq(); #endif - if(keyonly(1) && is_shift) + if(keyonly(1)) { + if(is_shift) + { char Buf[4096]; - fprintf(stderr, "Which file to create? (empty to cancel): "); fflush(stderr); + fprintf(stderr, "Which movie file to create? (empty to cancel): "); fflush(stderr); fgets(Buf, sizeof Buf, stdin); strtok(Buf, "\r\n"); if(*Buf) { - FCEUI_SaveMovie(Buf, 0, NULL); + FCEUI_SaveMovie(Buf, MOVIE_FLAG_FROM_RESET, NULL); } else fprintf(stderr, "Cancelled\n"); + } + else + keyonce[MKK(1)] = 0; } - if(keyonly(2) && is_shift) + if(keyonly(2)) { + if(is_shift) + { char Buf[4096]; - fprintf(stderr, "Which file to load? (empty to cancel): "); fflush(stderr); + fprintf(stderr, "Which movie file to load? (empty to cancel): "); fflush(stderr); fgets(Buf, sizeof Buf, stdin); strtok(Buf, "\r\n"); if(*Buf) { - extern int LoggingEnabled; - LoggingEnabled = 1; FCEUI_LoadMovie(Buf, 0); } else fprintf(stderr, "Cancelled\n"); + } + else + keyonce[MKK(2)] = 0; } - if(keyonly(3) && is_shift) + if(keyonly(3)) { - FCEUI_StopMovie(); + if(is_shift) + FCEUI_StopMovie(); + else + keyonce[MKK(3)] = 0; } if(keyonly(F5) || keyonly(S)) { FCEUI_SaveState(NULL); } +/* if(keyonly(F7) || keyonly(F)) { FCEUI_LoadState(NULL); } +*/ } if(keyonly(F1)) FCEUI_ToggleTileView(); - if(keyonly(MINUS)) DecreaseEmulationSpeed(); - if(keyonly(EQUAL)) IncreaseEmulationSpeed(); + if(keyonly(KP_MINUS) || keyonly(N)) DecreaseEmulationSpeed(); + if(keyonly(KP_PLUS) || keyonly(M)) IncreaseEmulationSpeed(); if(keyonly(BACKSPACE)) FCEUI_MovieToggleFrameDisplay(); - if(keyonly(BACKSLASH)) FCEUI_ToggleEmulationPause(); - if(keyonly(RIGHTCONTROL)) FCEUI_FrameAdvance(); + if(keyonly(ENTER)) FCEUI_ToggleEmulationPause(); + if(keyonly(QUOTE)) FCEUI_FrameAdvance(); if(keyonly(F10)) FCEUI_ResetNES(); if(keyonly(F11)) FCEUI_PowerNES(); @@ -237,6 +260,7 @@ if(KEY(F12) || KEY(ESCAPE)) CloseGame(); #endif +#if 0 if(gametype==GIT_VSUNI) { if(keyonly(F8)) FCEUI_VSUniCoin(); @@ -256,6 +280,7 @@ if(keyonly(8)) FCEUI_VSUniToggleDIP(7); } else +#endif { static uint8 bbuf[32]; static int bbuft; @@ -289,10 +314,12 @@ #define SSM(x) \ { if(barcoder) { if(bbuft < 13) {bbuf[bbuft++] = '0' + x; bbuf[bbuft] = 0;} FCEUI_DispMessage("Barcode: %s",bbuf);} \ else { \ - if(!is_shift) FCEUI_SelectState(x); \ + if(!is_shift) FCEUI_SelectState(x, 1); \ } } DIPSless: + if(is_alt && !is_shift && !is_ctrl) + { if(keyonly(0)) SSM(0); if(keyonly(1)) SSM(1); if(keyonly(2)) SSM(2); @@ -303,6 +330,7 @@ if(keyonly(7)) SSM(7); if(keyonly(8)) SSM(8); if(keyonly(9)) SSM(9); + } #undef SSM } } @@ -317,8 +345,14 @@ ButtConfig GamePadConfig[4][10]={ /* Gamepad 1 */ { - MK(KP3), MK(KP2), MK(TAB), MK(ENTER), MK(W),MK(Z), - MK(A), MK(S), MKZ(), MKZ() + MK(D),MK(A), + MK(H),MK(P), + + MK(CURSORUP),MK(CURSORDOWN), + MK(CURSORLEFT),MK(CURSORRIGHT), + /* arrows */ + + MKZ(), MKZ() }, /* Gamepad 2 */ @@ -353,12 +387,14 @@ JS|=(1<pixels, 256,tlines); - } + +#if NESVIDEOS_TRACKING + TILE_TrackFrame(screen->pixels, 256, tlines); #endif - + + if(screen->flags&SDL_DOUBLEBUF) SDL_Flip(screen); } diff -NaHudr b/src/drivers/pc/tiletracker.cc a/src/drivers/pc/tiletracker.cc --- b/src/drivers/pc/tiletracker.cc 1970-01-01 02:00:00.000000000 +0200 +++ a/src/drivers/pc/tiletracker.cc 2005-04-07 22:26:24.000000000 +0300 @@ -0,0 +1,262 @@ +#include "tiletracker.hh" + +#if NESVIDEOS_TRACKING + +#include +#include +#include + +typedef unsigned int uint32 ; +typedef unsigned char uint8 ; +typedef unsigned short uint16; + +#include "doubledeque.hh" + +class TILE_Tracker +{ + /* In this tracker, alpha = visibility. 0=transparent */ + static const unsigned max_x = 256; + static const unsigned max_y = 224; + static const unsigned max = max_x * max_y; + uint16 CurrentScreen[max]; + + class Layer + { + int org_x, org_y; + + int xmin,ymin; + int xmax,ymax; + bool first; + + unsigned count; + + int get_min_y() const { return ymin; } + int get_max_y() const { return ymax; } + int get_min_x() const { return xmin; } + int get_max_x() const { return xmax; } + + class UncertainPixel + { + unsigned r,g,b; + unsigned n; + unsigned pix; + public: + UncertainPixel() : r(0),g(0),b(0),n(0), pix(0x404040) + { + } + void set(unsigned R,unsigned G,unsigned B) + { + r+=R; g+=G; b+=B; + ++n; + + pix = (((r/n) << 16) + ((g/n) << 8) + (b/n)); + } + operator uint32() const { return pix; } + }; + + DoubleDeque screens; + + const std::vector LoadScreen(int ox,int oy, unsigned sx,unsigned sy) + { + std::vector result(sy*sx, 0); + unsigned pos=0; + for(unsigned y=0; y::Row& row = screens.getRow(y+oy); + for(unsigned x=0; x> (11-3)) & 0xF8; + unsigned g = (pix16 >> (5-2)) & 0xFC; + unsigned b = (pix16 << -(0-3)) & 0xF8; + screens.at(y+oy, x+ox).set(r,g,b); + } + } + void Save() + { + if(first) return; + + int ymi = get_min_y(), yma = get_max_y(); + int xmi = get_min_x(), xma = get_max_x(); + + unsigned wid = xma-xmi+1; + unsigned hei = yma-ymi+1; + + if(wid == 1 || hei == 1) return; + + fprintf(stderr, " (%d,%d)-(%d,%d)\n", xmi,ymi, xma,yma); + + std::vector screen = LoadScreen(xmi,ymi, wid,hei); + + gdImagePtr im = gdImageCreateTrueColor(wid,hei); + + for(unsigned p=0, y=0; y> 24) & 0xFF, + (pix32 >> 16) & 0xFF, + (pix32 >> 8) & 0xFF + )*/; + gdImageSetPixel(im, x,y, pix); + } + + char Filename[512]; + sprintf(Filename, "tile-%04u.png", count); + + FILE* fp = fopen(Filename, "wb"); + gdImagePng(im, fp); + fclose(fp); + gdImageDestroy(im); + } + + public: + Layer() : count(0) + { + Reset(); + } + ~Layer() + { + } + + void Reset() + { + Save(); + + fprintf(stderr, " Too different\n"); + screens.clear(); + org_x = 0x40000000; + org_y = 0x40000000; + ++count; + first = true; + } + + void FitScreen(const uint16* buf, int bestdx, int bestdy, bool suspect) + { + static unsigned framecounter=0; + if(++framecounter == 600) { Save(); framecounter=0; } + + if(bestdx != 0 || bestdy != 0) + { + fprintf(stderr, " Motion(%d,%d), Origo(%d,%d)\n", bestdx,bestdy, org_x,org_y); + } + + org_x += bestdx; org_y += bestdy; + + if(suspect) + { + std::vector oldbuf = LoadScreen(org_x,org_y, max_x,max_y); + unsigned diff = 0; + for(unsigned a=0; a> (11-3)) & 0xF8; + unsigned g = (pix16 >> (5-2)) & 0xFC; + unsigned b = (pix16 << -(0-3)) & 0xF8; + unsigned oldr = ((pix >> 16) & 0xFF); + unsigned oldg = ((pix >> 8) & 0xFF); + unsigned oldb = ((pix >> 0) & 0xFF); + int rdiff = (int)(r-oldr); if(rdiff < 0)rdiff=-rdiff; + int gdiff = (int)(g-oldg); if(gdiff < 0)gdiff=-gdiff; + int bdiff = (int)(b-oldb); if(bdiff < 0)bdiff=-bdiff; + unsigned absdiff = rdiff+gdiff+bdiff; + diff += absdiff; + } + if(diff > max_x * 256) + { + Reset(); + } + } + + if(first || org_x < xmin) xmin = org_x; + if(first || org_y < ymin) ymin = org_y; + int xtmp = org_x+max_x; if(first || xtmp > xmax) xmax=xtmp; + int ytmp = org_y+max_y; if(first || ytmp > ymax) ymax=ytmp; + first=false; + + PutScreen(buf, org_x,org_y, max_x,max_y); + } + } layer; + +public: + TILE_Tracker() + { + } + + void Reset() + { + layer.Reset(); + } + + void Begin() + { + for(unsigned a=0; a= max) return; /* silently ignore bad coordinate */ + //fprintf(stderr, "[%u]", pos); + CurrentScreen[pos] = pixel; + } +} TILE_Tracker; + +extern "C" { /******* PPU variables: **/ + +/* 0..7. Finetuning the scrolling. */ +unsigned VScroll=0; +unsigned HScroll=0; +unsigned NTAWrites=0; + +void TILE_TrackFrame(const void*data, unsigned width, unsigned height) +{ + TILE_Tracker.Begin(); + + const unsigned short * buf = (const unsigned short *)data; + unsigned pos=0; + for(unsigned y=0; y= 128) hdiff -= 256; + if(vdiff >= 120) vdiff -= 240; + + long absdiff2 = (hdiff*hdiff) + (vdiff*vdiff); + + bool suspect = false; + if(/*absdiff2 > 20*20 || */NTAWrites > 200) + { + suspect = true; + } + +/* + if(NTAWrites != 0) + fprintf(stderr, "%ld NTA writes\n", NTAWrites); +*/ + TILE_Tracker.End(hdiff, vdiff, suspect); + NTAWrites = 0; +} + +} + +#endif diff -NaHudr b/src/drivers/pc/tiletracker.hh a/src/drivers/pc/tiletracker.hh --- b/src/drivers/pc/tiletracker.hh 1970-01-01 02:00:00.000000000 +0200 +++ a/src/drivers/pc/tiletracker.hh 2005-04-07 20:51:34.000000000 +0300 @@ -0,0 +1,9 @@ +#define NESVIDEOS_TRACKING 1 + +#ifdef __cplusplus +extern "C" { +#endif +extern void TILE_TrackFrame(const void*data, unsigned width, unsigned height); +#ifdef __cplusplus +} +#endif diff -NaHudr b/src/ppu.c a/src/ppu.c --- b/src/ppu.c 2004-08-18 01:18:51.000000000 +0300 +++ a/src/ppu.c 2005-04-07 21:26:56.000000000 +0300 @@ -282,7 +282,13 @@ PPUSPL++; } - + +/* Begin Bisqwit's TILE_TRACKER */ +unsigned VScroll; +unsigned HScroll; +unsigned NTAWrites; +/* End Bisqwit's TILE_TRACKER */ + static DECLFW(B2005) { uint32 tmp=TempAddr; @@ -293,15 +299,20 @@ tmp&=0xFFE0; tmp|=V>>3; XOffset=V&7; + if(scanline>=224 || scanline==0) HScroll=V; } else { tmp&=0x8C1F; tmp|=((V&~0x7)<<2); tmp|=(V&7)<<12; + if(scanline>=224 || scanline==0) VScroll=V; } TempAddr=tmp; - vtoggle^=1; + vtoggle^=1; /* + if(!vtoggle) + fprintf(stderr, "Scroll %u,%u @ %u\n", + HScroll,VScroll, scanline);*/ } @@ -347,7 +358,10 @@ else { if(PPUNTARAM&(1<<((tmp&0xF00)>>10))) + { vnapage[((tmp&0xF00)>>10)][tmp&0x3FF]=V; + ++NTAWrites; + } } if (INC32) RefreshAddr+=32; else RefreshAddr++; @@ -530,6 +544,7 @@ { InputScanlineHook(Plinef,spork?sprlinebuf:0,linestartts,lasttile*8-16); } + NTAWrites++; return; }