blargg wrote:
I think that a NES emulator library that's portable and has a clean interface is an asset. It's worth the experience making something really clean and easy to use, as that's often lacking. I aimed for too much performance and made the implementation more complex than was maintainable, and it suffered.
I'm not saying it's perfect...but...
The library I linked has no reliance on any sound or video production libraries. It provides bitmasks for reference so you can pass the controller bits in the right order--but otherwise makes no reference to keyboard, joystick, mouse, or other input technologies. nesSetControllerScreenPosition, for example, could be set from a mouse's position or some other position-aware input device. I admit that the nes_emulator_core.h file could use a lot of clean up...lots of stuff in there that should be elsewhere, but the main gist of the library (with some corrections...some comments were slightly wrong) is:
Code:
// Exported interfaces.
// The following interfaces are to be used by a UI to interact with the emulation
// core and perform the necessary steps to emulate a NES game. Those steps are:
// 1. Set the NES system mode to MODE_NTSC, MODE_DENDY or MODE_PAL using nesSetSystemMode().
// 2. Provide a 256x256x4-byte chunk of memory to the emulator core for it to
// render the NES TV surface onto, using nesSetTVOut().
// 3. Clear any emulation state by using nesUnloadROM().
// 4. Pass 16KB PRG-ROM banks in order and 8KB CHR-ROM banks in order to the emulation
// core by using nesLoadPRGROMBank() and nesLoadCHRROMBank() respectively. If no
// CHR-ROM banks are present, do not call nesLoadCHRROMBank().
// 5. If the game has fixed mirroring, tell the emulator core which one it is by
// using nesSetHorizontalMirroring() or nesSetVerticalMirroring().
// 6. Tell the emulator core you're done passing it ROM data by using
// nesLoadROM().
// 7. Cause the loaded ROM to be recognized by the emulator core by issuing a
// reset. Use the nesResetInitial(mapper) variant to set up the emulator core with the
// appropriate mapper for the loaded ROM. Subsequent resets can use the nesReset()
// variant.
// 8. Run a PPU (video) frame's worth of NES emulation, which generates a full
// rendered video frame and an appropriate amount of audio data, by using
// nesRun(). Pass in collected joypad input data.
// 9. If the emulator supports sound output, the number of audio samples available
// can be retrieved by using nesGetAudioSamplesAvailable(). A pointer to the
// next buffer of audio samples to play can be retrieved using nesGetAudioSamples().
// Once retrieved, the number of available audio samples should be reset using
// nesClearAudioSamplesAvailable.
// Emulation interfaces.
void nesSetSystemMode ( uint32_t mode );
uint32_t nesGetSystemMode ( void );
void nesSetTVOut ( int8_t* tv );
void nesUnloadROM ( void );
void nesLoadPRGROMBank ( uint32_t bank, uint8_t* bankData );
void nesLoadCHRROMBank ( uint32_t bank, uint8_t* bankData );
void nesSetHorizontalMirroring ( void );
void nesSetVerticalMirroring ( void );
void nesSetFourScreen ( void );
void nesLoadROM ( void );
void nesResetInitial ( uint32_t mapper );
void nesReset ( bool soft );
void nesRun ( uint32_t* joypads );
int32_t nesGetAudioSamplesAvailable ( void );
void nesClearAudioSamplesAvailable ( void );
uint8_t* nesGetAudioSamples ( uint16_t samples );
void nesSetControllerType ( int32_t port, int32_t type );
void nesSetControllerScreenPosition ( int32_t port, int32_t px, int32_t py, int32_t wx1, int32_t wy1, int32_t wx2, int32_t wy2 );
void nesSetControllerSpecial ( int32_t port, int32_t special );
bool nesROMIsLoaded ( void );