Libretro: Add GB/GBC core
Gb,gbc and sgb enhanced version of roms and savestates working. Bios loading for gb/gbc works too. No save ram / battery handling yet. Fix offset and pitch issues with vba rendering and when borders are enabled.
This commit is contained in:
parent
f05a05e622
commit
bf447bf89a
377
src/gb/GB.cpp
377
src/gb/GB.cpp
|
@ -2852,6 +2852,7 @@ void gbReset()
|
|||
gbCheatWrite(true); // Emulates GS codes.
|
||||
}
|
||||
|
||||
#ifndef __LIBRETRO__
|
||||
void gbWriteSaveMBC1(const char* name)
|
||||
{
|
||||
if (gbRam) {
|
||||
|
@ -3335,6 +3336,7 @@ bool gbReadSaveMMM01(const char* name)
|
|||
} else
|
||||
return false;
|
||||
}
|
||||
#endif // !__LIBRETRO__
|
||||
|
||||
void gbInit()
|
||||
{
|
||||
|
@ -3343,11 +3345,16 @@ void gbInit()
|
|||
|
||||
gbMemory = (uint8_t*)malloc(65536);
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
pix = (uint8_t*)calloc(1, 4 * 256 * 224);
|
||||
#else
|
||||
pix = (uint8_t*)calloc(1, 4 * 257 * 226);
|
||||
#endif
|
||||
|
||||
gbLineBuffer = (uint16_t*)malloc(160 * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
#ifndef __LIBRETRO__
|
||||
bool gbWriteBatteryFile(const char* file, bool extendedSave)
|
||||
{
|
||||
if (gbBattery) {
|
||||
|
@ -3480,6 +3487,7 @@ bool gbReadBatteryFile(const char* file)
|
|||
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
|
||||
return res;
|
||||
}
|
||||
#endif // !__LIBRETRO__
|
||||
|
||||
bool gbReadGSASnapshot(const char* fileName)
|
||||
{
|
||||
|
@ -3617,6 +3625,7 @@ variable_desc gbSaveGameStruct[] = {
|
|||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
#ifndef __LIBRETRO__
|
||||
static bool gbWriteSaveState(gzFile gzFile)
|
||||
{
|
||||
|
||||
|
@ -4091,6 +4100,7 @@ bool gbReadSaveState(const char* name)
|
|||
|
||||
return res;
|
||||
}
|
||||
#endif // !__LIBRETRO__
|
||||
|
||||
bool gbWritePNGFile(const char* fileName)
|
||||
{
|
||||
|
@ -4457,8 +4467,13 @@ void gbDrawLine()
|
|||
{
|
||||
switch (systemColorDepth) {
|
||||
case 16: {
|
||||
#ifdef __LIBRETRO__
|
||||
uint16_t* dest = (uint16_t*)pix + gbBorderLineSkip * (register_LY + gbBorderRowSkip)
|
||||
+ gbBorderColumnSkip;
|
||||
#else
|
||||
uint16_t* dest = (uint16_t*)pix + (gbBorderLineSkip + 2) * (register_LY + gbBorderRowSkip + 1)
|
||||
+ gbBorderColumnSkip;
|
||||
#endif
|
||||
for (int x = 0; x < 160;) {
|
||||
*dest++ = systemColorMap16[gbLineMix[x++]];
|
||||
*dest++ = systemColorMap16[gbLineMix[x++]];
|
||||
|
@ -4482,7 +4497,9 @@ void gbDrawLine()
|
|||
}
|
||||
if (gbBorderOn)
|
||||
dest += gbBorderColumnSkip;
|
||||
#ifndef __LIBRETRO__
|
||||
*dest++ = 0; // for filters that read one pixel more
|
||||
#endif
|
||||
} break;
|
||||
|
||||
case 24: {
|
||||
|
@ -4527,8 +4544,13 @@ void gbDrawLine()
|
|||
} break;
|
||||
|
||||
case 32: {
|
||||
#ifdef __LIBRETRO__
|
||||
uint32_t* dest = (uint32_t*)pix + gbBorderLineSkip * (register_LY + gbBorderRowSkip)
|
||||
+ gbBorderColumnSkip;
|
||||
#else
|
||||
uint32_t* dest = (uint32_t*)pix + (gbBorderLineSkip + 1) * (register_LY + gbBorderRowSkip + 1)
|
||||
+ gbBorderColumnSkip;
|
||||
#endif
|
||||
for (int x = 0; x < 160;) {
|
||||
*dest++ = systemColorMap32[gbLineMix[x++]];
|
||||
*dest++ = systemColorMap32[gbLineMix[x++]];
|
||||
|
@ -5418,6 +5440,361 @@ void gbEmulate(int ticksToStop)
|
|||
}
|
||||
}
|
||||
|
||||
bool gbLoadRomData(const char* data, unsigned size)
|
||||
{
|
||||
gbRomSize = size;
|
||||
if (gbRom != NULL) {
|
||||
gbCleanUp();
|
||||
}
|
||||
|
||||
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
|
||||
|
||||
gbRom = (uint8_t*)calloc(1, gbRomSize);
|
||||
if (gbRom == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(gbRom, data, gbRomSize);
|
||||
|
||||
gbBatteryError = false;
|
||||
|
||||
if (bios != NULL) {
|
||||
free(bios);
|
||||
bios = NULL;
|
||||
}
|
||||
bios = (uint8_t*)calloc(1, 0x900);
|
||||
|
||||
return gbUpdateSizes();
|
||||
}
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
#include <stddef.h>
|
||||
|
||||
unsigned int gbWriteSaveState(uint8_t* data, unsigned)
|
||||
{
|
||||
uint8_t* orig = data;
|
||||
|
||||
utilWriteIntMem(data, GBSAVE_GAME_VERSION);
|
||||
|
||||
utilWriteMem(data, &gbRom[0x134], 15);
|
||||
|
||||
utilWriteIntMem(data, useBios);
|
||||
utilWriteIntMem(data, inBios);
|
||||
|
||||
utilWriteDataMem(data, gbSaveGameStruct);
|
||||
|
||||
utilWriteMem(data, &IFF, 2);
|
||||
|
||||
if (gbSgbMode) {
|
||||
gbSgbSaveGame(data);
|
||||
}
|
||||
|
||||
utilWriteMem(data, &gbDataMBC1, sizeof(gbDataMBC1));
|
||||
utilWriteMem(data, &gbDataMBC2, sizeof(gbDataMBC2));
|
||||
utilWriteMem(data, &gbDataMBC3, sizeof(gbDataMBC3));
|
||||
utilWriteMem(data, &gbDataMBC5, sizeof(gbDataMBC5));
|
||||
utilWriteMem(data, &gbDataHuC1, sizeof(gbDataHuC1));
|
||||
utilWriteMem(data, &gbDataHuC3, sizeof(gbDataHuC3));
|
||||
utilWriteMem(data, &gbDataTAMA5, sizeof(gbDataTAMA5));
|
||||
if (gbTAMA5ram != NULL)
|
||||
utilWriteMem(data, gbTAMA5ram, gbTAMA5ramSize);
|
||||
utilWriteMem(data, &gbDataMMM01, sizeof(gbDataMMM01));
|
||||
|
||||
utilWriteMem(data, gbPalette, 128 * sizeof(uint16_t));
|
||||
|
||||
utilWriteMem(data, &gbMemory[0x8000], 0x8000);
|
||||
|
||||
if (gbRamSize && gbRam) {
|
||||
utilWriteIntMem(data, gbRamSize);
|
||||
utilWriteMem(data, gbRam, gbRamSize);
|
||||
}
|
||||
|
||||
if (gbCgbMode) {
|
||||
utilWriteMem(data, gbVram, 0x4000);
|
||||
utilWriteMem(data, gbWram, 0x8000);
|
||||
}
|
||||
|
||||
gbSoundSaveGame(data);
|
||||
|
||||
// We dont care about cheat saves
|
||||
// gbCheatsSaveGame(data);
|
||||
|
||||
utilWriteIntMem(data, gbLcdModeDelayed);
|
||||
utilWriteIntMem(data, gbLcdTicksDelayed);
|
||||
utilWriteIntMem(data, gbLcdLYIncrementTicksDelayed);
|
||||
utilWriteIntMem(data, gbSpritesTicks[299]);
|
||||
utilWriteIntMem(data, gbTimerModeChange);
|
||||
utilWriteIntMem(data, gbTimerOnChange);
|
||||
utilWriteIntMem(data, gbHardware);
|
||||
utilWriteIntMem(data, gbBlackScreen);
|
||||
utilWriteIntMem(data, oldRegister_WY);
|
||||
utilWriteIntMem(data, gbWindowLine);
|
||||
utilWriteIntMem(data, inUseRegister_WY);
|
||||
utilWriteIntMem(data, gbScreenOn);
|
||||
utilWriteIntMem(data, 0x12345678); // end marker
|
||||
|
||||
return (ptrdiff_t)data - (ptrdiff_t)orig;
|
||||
}
|
||||
|
||||
bool gbReadSaveState(const uint8_t* data, unsigned)
|
||||
{
|
||||
int version = utilReadIntMem(data);
|
||||
|
||||
if (version != GBSAVE_GAME_VERSION) {
|
||||
systemMessage(MSG_UNSUPPORTED_VB_SGM,
|
||||
N_("Unsupported VBA-M save game version %d"), version);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t romname[20];
|
||||
|
||||
utilReadMem(romname, data, 15);
|
||||
|
||||
if (memcmp(&gbRom[0x134], romname, 15) != 0) {
|
||||
systemMessage(MSG_CANNOT_LOAD_SGM_FOR,
|
||||
N_("Cannot load save game for %s. Playing %s"),
|
||||
romname, &gbRom[0x134]);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ub = false;
|
||||
bool ib = false;
|
||||
|
||||
ub = utilReadIntMem(data) ? true : false;
|
||||
ib = utilReadIntMem(data) ? true : false;
|
||||
|
||||
if ((ub != useBios) && (ib)) {
|
||||
if (useBios)
|
||||
systemMessage(MSG_SAVE_GAME_NOT_USING_BIOS,
|
||||
N_("Save game is not using the BIOS files"));
|
||||
else
|
||||
systemMessage(MSG_SAVE_GAME_USING_BIOS,
|
||||
N_("Save game is using the BIOS file"));
|
||||
return false;
|
||||
}
|
||||
|
||||
gbReset();
|
||||
|
||||
inBios = ib;
|
||||
|
||||
utilReadDataMem(data, gbSaveGameStruct);
|
||||
|
||||
// Correct crash when loading color gameboy save in regular gameboy type.
|
||||
if (!gbCgbMode) {
|
||||
if (gbVram != NULL) {
|
||||
free(gbVram);
|
||||
gbVram = NULL;
|
||||
}
|
||||
if (gbWram != NULL) {
|
||||
free(gbWram);
|
||||
gbWram = NULL;
|
||||
}
|
||||
} else {
|
||||
if (gbVram == NULL)
|
||||
gbVram = (uint8_t*)malloc(0x4000);
|
||||
if (gbWram == NULL)
|
||||
gbWram = (uint8_t*)malloc(0x8000);
|
||||
memset(gbVram, 0, 0x4000);
|
||||
memset(gbPalette, 0, 2 * 128);
|
||||
}
|
||||
|
||||
utilReadMem(&IFF, data, 2);
|
||||
|
||||
if (gbSgbMode) {
|
||||
gbSgbReadGame(data, version);
|
||||
} else {
|
||||
gbSgbMask = 0; // loading a game at the wrong time causes no display
|
||||
}
|
||||
|
||||
utilReadMem(&gbDataMBC1, data, sizeof(gbDataMBC1));
|
||||
utilReadMem(&gbDataMBC2, data, sizeof(gbDataMBC2));
|
||||
utilReadMem(&gbDataMBC3, data, sizeof(gbDataMBC3));
|
||||
utilReadMem(&gbDataMBC5, data, sizeof(gbDataMBC5));
|
||||
utilReadMem(&gbDataHuC1, data, sizeof(gbDataHuC1));
|
||||
utilReadMem(&gbDataHuC3, data, sizeof(gbDataHuC3));
|
||||
utilReadMem(&gbDataTAMA5, data, sizeof(gbDataTAMA5));
|
||||
if (gbTAMA5ram != NULL) {
|
||||
utilReadMem(gbTAMA5ram, data, gbTAMA5ramSize);
|
||||
}
|
||||
utilReadMem(&gbDataMMM01, data, sizeof(gbDataMMM01));
|
||||
|
||||
utilReadMem(gbPalette, data, 128 * sizeof(uint16_t));
|
||||
|
||||
utilReadMem(&gbMemory[0x8000], data, 0x8000);
|
||||
|
||||
if (gbRamSize && gbRam) {
|
||||
int ramSize = utilReadIntMem(data);
|
||||
utilReadMem(gbRam, data, (gbRamSize > ramSize) ? ramSize : gbRamSize); //read
|
||||
/*if (ramSize > gbRamSize)
|
||||
utilGzSeek(gzFile, ramSize - gbRamSize, SEEK_CUR);*/ // Libretro Note: ????
|
||||
}
|
||||
|
||||
memset(gbSCYLine, register_SCY, sizeof(gbSCYLine));
|
||||
memset(gbSCXLine, register_SCX, sizeof(gbSCXLine));
|
||||
memset(gbBgpLine, (gbBgp[0] | (gbBgp[1] << 2) | (gbBgp[2] << 4) | (gbBgp[3] << 6)), sizeof(gbBgpLine));
|
||||
memset(gbObp0Line, (gbObp0[0] | (gbObp0[1] << 2) | (gbObp0[2] << 4) | (gbObp0[3] << 6)), sizeof(gbObp0Line));
|
||||
memset(gbObp1Line, (gbObp1[0] | (gbObp1[1] << 2) | (gbObp1[2] << 4) | (gbObp1[3] << 6)), sizeof(gbObp1Line));
|
||||
memset(gbSpritesTicks, 0x0, sizeof(gbSpritesTicks));
|
||||
|
||||
if (inBios) {
|
||||
gbMemoryMap[0x00] = &gbMemory[0x0000];
|
||||
if (gbHardware & 5) {
|
||||
memcpy((uint8_t*)(gbMemory), (uint8_t*)(gbRom), 0x1000);
|
||||
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x100);
|
||||
} else if (gbHardware & 2) {
|
||||
memcpy((uint8_t*)(gbMemory), (uint8_t*)(bios), 0x900);
|
||||
memcpy((uint8_t*)(gbMemory + 0x100), (uint8_t*)(gbRom + 0x100), 0x100);
|
||||
}
|
||||
|
||||
} else {
|
||||
gbMemoryMap[0x00] = &gbRom[0x0000];
|
||||
}
|
||||
|
||||
gbMemoryMap[0x01] = &gbRom[0x1000];
|
||||
gbMemoryMap[0x02] = &gbRom[0x2000];
|
||||
gbMemoryMap[0x03] = &gbRom[0x3000];
|
||||
gbMemoryMap[0x04] = &gbRom[0x4000];
|
||||
gbMemoryMap[0x05] = &gbRom[0x5000];
|
||||
gbMemoryMap[0x06] = &gbRom[0x6000];
|
||||
gbMemoryMap[0x07] = &gbRom[0x7000];
|
||||
gbMemoryMap[0x08] = &gbMemory[0x8000];
|
||||
gbMemoryMap[0x09] = &gbMemory[0x9000];
|
||||
gbMemoryMap[0x0a] = &gbMemory[0xa000];
|
||||
gbMemoryMap[0x0b] = &gbMemory[0xb000];
|
||||
gbMemoryMap[0x0c] = &gbMemory[0xc000];
|
||||
gbMemoryMap[0x0d] = &gbMemory[0xd000];
|
||||
gbMemoryMap[0x0e] = &gbMemory[0xe000];
|
||||
gbMemoryMap[0x0f] = &gbMemory[0xf000];
|
||||
|
||||
switch (gbRomType) {
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
// MBC 1
|
||||
memoryUpdateMapMBC1();
|
||||
break;
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
// MBC2
|
||||
memoryUpdateMapMBC2();
|
||||
break;
|
||||
case 0x0b:
|
||||
case 0x0c:
|
||||
case 0x0d:
|
||||
// MMM01
|
||||
memoryUpdateMapMMM01();
|
||||
break;
|
||||
case 0x0f:
|
||||
case 0x10:
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
case 0x13:
|
||||
// MBC 3
|
||||
memoryUpdateMapMBC3();
|
||||
break;
|
||||
case 0x19:
|
||||
case 0x1a:
|
||||
case 0x1b:
|
||||
// MBC5
|
||||
memoryUpdateMapMBC5();
|
||||
break;
|
||||
case 0x1c:
|
||||
case 0x1d:
|
||||
case 0x1e:
|
||||
// MBC 5 Rumble
|
||||
memoryUpdateMapMBC5();
|
||||
break;
|
||||
case 0x22:
|
||||
// MBC 7
|
||||
memoryUpdateMapMBC7();
|
||||
break;
|
||||
case 0x56:
|
||||
// GS3
|
||||
memoryUpdateMapGS3();
|
||||
break;
|
||||
case 0xfd:
|
||||
// TAMA5
|
||||
memoryUpdateMapTAMA5();
|
||||
break;
|
||||
case 0xfe:
|
||||
// HuC3
|
||||
memoryUpdateMapHuC3();
|
||||
break;
|
||||
case 0xff:
|
||||
// HuC1
|
||||
memoryUpdateMapHuC1();
|
||||
break;
|
||||
}
|
||||
|
||||
if (gbCgbMode) {
|
||||
utilReadMem(gbVram, data, 0x4000);
|
||||
utilReadMem(gbWram, data, 0x8000);
|
||||
|
||||
int value = register_SVBK;
|
||||
if (value == 0)
|
||||
value = 1;
|
||||
|
||||
gbMemoryMap[0x08] = &gbVram[register_VBK * 0x2000];
|
||||
gbMemoryMap[0x09] = &gbVram[register_VBK * 0x2000 + 0x1000];
|
||||
gbMemoryMap[0x0d] = &gbWram[value * 0x1000];
|
||||
}
|
||||
|
||||
gbSoundReadGame(data, version);
|
||||
|
||||
if (gbCgbMode && gbSgbMode) {
|
||||
gbSgbMode = 0;
|
||||
}
|
||||
|
||||
if (gbBorderOn && !gbSgbMask) {
|
||||
gbSgbRenderBorder();
|
||||
}
|
||||
|
||||
gbLcdModeDelayed = utilReadIntMem(data);
|
||||
gbLcdTicksDelayed = utilReadIntMem(data);
|
||||
gbLcdLYIncrementTicksDelayed = utilReadIntMem(data);
|
||||
gbSpritesTicks[299] = utilReadIntMem(data) & 0xff;
|
||||
gbTimerModeChange = (utilReadIntMem(data) ? true : false);
|
||||
gbTimerOnChange = (utilReadIntMem(data) ? true : false);
|
||||
gbHardware = utilReadIntMem(data);
|
||||
gbBlackScreen = (utilReadIntMem(data) ? true : false);
|
||||
oldRegister_WY = utilReadIntMem(data);
|
||||
gbWindowLine = utilReadIntMem(data);
|
||||
inUseRegister_WY = utilReadIntMem(data);
|
||||
gbScreenOn = (utilReadIntMem(data) ? true : false);
|
||||
|
||||
if (gbSpeed)
|
||||
gbLine99Ticks *= 2;
|
||||
|
||||
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
|
||||
|
||||
if (version >= 12 && utilReadIntMem(data) != 0x12345678)
|
||||
assert(false); // fails if something read too much/little from file
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gbWriteMemSaveState(char*, int, long&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gbReadMemSaveState(char*, int)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gbReadBatteryFile(const char*)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gbWriteBatteryFile(const char*)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct EmulatedSystem GBSystem = {
|
||||
// emuMain
|
||||
gbEmulate,
|
||||
|
|
11
src/gb/gb.h
11
src/gb/gb.h
|
@ -31,18 +31,25 @@ void gbGetHardwareType();
|
|||
void gbReset();
|
||||
void gbCleanUp();
|
||||
void gbCPUInit(const char*, bool);
|
||||
#ifdef __LIBRETRO__
|
||||
unsigned int gbWriteSaveState(uint8_t*, unsigned);
|
||||
bool gbReadSaveState(const uint8_t*, unsigned);
|
||||
#else
|
||||
bool gbWriteSaveState(const char*);
|
||||
bool gbReadSaveState(const char*);
|
||||
#endif
|
||||
bool gbWriteBatteryFile(const char*);
|
||||
bool gbWriteBatteryFile(const char*, bool);
|
||||
bool gbReadBatteryFile(const char*);
|
||||
bool gbWriteSaveState(const char*);
|
||||
bool gbWriteMemSaveState(char*, int, long&);
|
||||
bool gbReadSaveState(const char*);
|
||||
bool gbReadMemSaveState(char*, int);
|
||||
void gbSgbRenderBorder();
|
||||
bool gbWritePNGFile(const char*);
|
||||
bool gbWriteBMPFile(const char*);
|
||||
bool gbReadGSASnapshot(const char*);
|
||||
|
||||
bool gbLoadRomData(const char* data, unsigned size);
|
||||
|
||||
extern int gbHardware;
|
||||
|
||||
extern struct EmulatedSystem GBSystem;
|
||||
|
|
|
@ -30,6 +30,7 @@ void gbCheatUpdateMap()
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef __LIBRETRO__
|
||||
void gbCheatsSaveGame(gzFile gzFile)
|
||||
{
|
||||
utilWriteInt(gzFile, gbCheatNumber);
|
||||
|
@ -98,6 +99,7 @@ void gbCheatsReadGameSkip(gzFile gzFile, int version)
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void gbCheatsSaveCheatList(const char* file)
|
||||
{
|
||||
|
|
|
@ -19,9 +19,11 @@ struct gbCheat {
|
|||
bool enabled;
|
||||
};
|
||||
|
||||
#ifndef __LIBRETRO__
|
||||
void gbCheatsSaveGame(gzFile);
|
||||
void gbCheatsReadGame(gzFile, int);
|
||||
void gbCheatsReadGameSkip(gzFile, int);
|
||||
#endif
|
||||
void gbCheatsSaveCheatList(const char*);
|
||||
bool gbCheatsLoadCheatList(const char*);
|
||||
bool gbCheatReadGSCodeFile(const char*);
|
||||
|
|
|
@ -113,7 +113,11 @@ void gbSgbFillScreen(uint16_t color)
|
|||
switch (systemColorDepth) {
|
||||
case 16: {
|
||||
for (int y = 0; y < 144; y++) {
|
||||
#ifdef __LIBRETRO__
|
||||
int yLine = (y + gbBorderRowSkip) * gbBorderLineSkip + gbBorderColumnSkip;
|
||||
#else
|
||||
int yLine = (y + gbBorderRowSkip + 1) * (gbBorderLineSkip + 2) + gbBorderColumnSkip;
|
||||
#endif
|
||||
uint16_t* dest = (uint16_t*)pix + yLine;
|
||||
for (register int x = 0; x < 160; x++)
|
||||
gbSgbDraw16Bit(dest++, color);
|
||||
|
@ -131,7 +135,11 @@ void gbSgbFillScreen(uint16_t color)
|
|||
} break;
|
||||
case 32: {
|
||||
for (int y = 0; y < 144; y++) {
|
||||
#ifdef __LIBRETRO__
|
||||
int yLine = (y + gbBorderRowSkip) * gbBorderLineSkip + gbBorderColumnSkip;
|
||||
#else
|
||||
int yLine = (y + gbBorderRowSkip + 1) * (gbBorderLineSkip + 1) + gbBorderColumnSkip;
|
||||
#endif
|
||||
uint32_t* dest = (uint32_t*)pix + yLine;
|
||||
for (register int x = 0; x < 160; x++) {
|
||||
gbSgbDraw32Bit(dest++, color);
|
||||
|
@ -181,9 +189,14 @@ void gbSgbRenderScreenToBuffer()
|
|||
|
||||
void gbSgbDrawBorderTile(int x, int y, int tile, int attr)
|
||||
{
|
||||
#ifdef __LIBRETRO__
|
||||
uint16_t* dest = (uint16_t*)pix + (y * 256) + x;
|
||||
uint32_t* dest32 = (uint32_t*)pix + (y * 256) + x;
|
||||
#else
|
||||
uint16_t* dest = (uint16_t*)pix + ((y + 1) * (256 + 2)) + x;
|
||||
uint32_t* dest32 = (uint32_t*)pix + ((y + 1) * 256 + 1) + x;
|
||||
#endif
|
||||
uint8_t* dest8 = (uint8_t*)pix + ((y * 256) + x) * 3;
|
||||
uint32_t* dest32 = (uint32_t*)pix + ((y + 1) * 257) + x;
|
||||
|
||||
uint8_t* tileAddress = &gbSgbBorderChar[tile * 32];
|
||||
uint8_t* tileAddress2 = &gbSgbBorderChar[tile * 32 + 16];
|
||||
|
@ -245,13 +258,21 @@ void gbSgbDrawBorderTile(int x, int y, int tile, int attr)
|
|||
|
||||
switch (systemColorDepth) {
|
||||
case 16:
|
||||
#ifdef __LIBRETRO__
|
||||
gbSgbDraw16Bit(dest + yyy * 256 + xxx, cc);
|
||||
#else
|
||||
gbSgbDraw16Bit(dest + yyy * (256 + 2) + xxx, cc);
|
||||
#endif
|
||||
break;
|
||||
case 24:
|
||||
gbSgbDraw24Bit(dest8 + (yyy * 256 + xxx) * 3, cc);
|
||||
break;
|
||||
case 32:
|
||||
#ifdef __LIBRETRO__
|
||||
gbSgbDraw32Bit(dest32 + yyy * 256 + xxx, cc);
|
||||
#else
|
||||
gbSgbDraw32Bit(dest32 + yyy * (256 + 1) + xxx, cc);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -860,6 +881,36 @@ variable_desc gbSgbSaveStructV3[] = {
|
|||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
void gbSgbSaveGame(uint8_t*& data)
|
||||
{
|
||||
utilWriteDataMem(data, gbSgbSaveStructV3);
|
||||
|
||||
utilWriteMem(data, gbSgbBorder, 2048);
|
||||
utilWriteMem(data, gbSgbBorderChar, 32 * 256);
|
||||
|
||||
utilWriteMem(data, gbSgbPacket, 16 * 7);
|
||||
|
||||
utilWriteMem(data, gbSgbSCPPalette, 4 * 512 * sizeof(uint16_t));
|
||||
utilWriteMem(data, gbSgbATF, 20 * 18);
|
||||
utilWriteMem(data, gbSgbATFList, 45 * 20 * 18);
|
||||
}
|
||||
|
||||
void gbSgbReadGame(const uint8_t*& data, int version)
|
||||
{
|
||||
utilReadDataMem(data, gbSgbSaveStructV3);
|
||||
|
||||
utilReadMem(gbSgbBorder, data, 2048);
|
||||
utilReadMem(gbSgbBorderChar, data, 32 * 256);
|
||||
|
||||
utilReadMem(gbSgbPacket, data, 16 * 7);
|
||||
|
||||
utilReadMem(gbSgbSCPPalette, data, 4 * 512 * sizeof(uint16_t));
|
||||
utilReadMem(gbSgbATF, data, 20 * 18);
|
||||
utilReadMem(gbSgbATFList, data, 45 * 20 * 18);
|
||||
}
|
||||
|
||||
#else // !__LIBRETRO__
|
||||
void gbSgbSaveGame(gzFile gzFile)
|
||||
{
|
||||
utilWriteData(gzFile, gbSgbSaveStructV3);
|
||||
|
@ -894,3 +945,4 @@ void gbSgbReadGame(gzFile gzFile, int version)
|
|||
utilGzRead(gzFile, gbSgbATF, 20 * 18);
|
||||
utilGzRead(gzFile, gbSgbATFList, 45 * 20 * 18);
|
||||
}
|
||||
#endif // !__LIBRETRO__
|
||||
|
|
|
@ -7,9 +7,14 @@ void gbSgbCommand();
|
|||
void gbSgbResetPacketState();
|
||||
void gbSgbReset();
|
||||
void gbSgbDoBitTransfer(uint8_t);
|
||||
void gbSgbRenderBorder();
|
||||
#ifdef __LIBRETRO__
|
||||
void gbSgbSaveGame(uint8_t*&);
|
||||
void gbSgbReadGame(const uint8_t*&, int);
|
||||
#else
|
||||
void gbSgbSaveGame(gzFile);
|
||||
void gbSgbReadGame(gzFile, int version);
|
||||
void gbSgbRenderBorder();
|
||||
#endif
|
||||
|
||||
extern uint8_t gbSgbATF[20 * 18];
|
||||
extern int gbSgbMode;
|
||||
|
|
|
@ -358,6 +358,7 @@ enum {
|
|||
nr52
|
||||
};
|
||||
|
||||
#ifndef __LIBRETRO__
|
||||
static void gbSoundReadGameOld(int version, gzFile gzFile)
|
||||
{
|
||||
if (version == 11) {
|
||||
|
@ -395,6 +396,7 @@ static void gbSoundReadGameOld(int version, gzFile gzFile)
|
|||
|
||||
memcpy(&s.regs[0x20], &gbMemory[0xFF30], 0x10); // wave
|
||||
}
|
||||
#endif
|
||||
|
||||
// New state format
|
||||
|
||||
|
@ -430,7 +432,11 @@ static variable_desc gb_state[] = {
|
|||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
void gbSoundSaveGame(uint8_t*& out)
|
||||
#else
|
||||
void gbSoundSaveGame(gzFile out)
|
||||
#endif
|
||||
{
|
||||
gb_apu->save_state(&state.apu);
|
||||
|
||||
|
@ -438,19 +444,31 @@ void gbSoundSaveGame(gzFile out)
|
|||
memset(dummy_state, 0, sizeof dummy_state);
|
||||
|
||||
state.version = 1;
|
||||
#ifdef __LIBRETRO__
|
||||
utilWriteDataMem(out, gb_state);
|
||||
#else
|
||||
utilWriteData(out, gb_state);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
void gbSoundReadGame(const uint8_t*& in, int version)
|
||||
#else
|
||||
void gbSoundReadGame(int version, gzFile in)
|
||||
#endif
|
||||
{
|
||||
// Prepare APU and default state
|
||||
reset_apu();
|
||||
gb_apu->save_state(&state.apu);
|
||||
|
||||
if (version > 11)
|
||||
#ifdef __LIBRETRO__
|
||||
utilReadDataMem(in, gb_state);
|
||||
#else
|
||||
utilReadData(in, gb_state);
|
||||
else
|
||||
gbSoundReadGameOld(version, in);
|
||||
#endif
|
||||
|
||||
gb_apu->load_state(state.apu);
|
||||
}
|
||||
|
|
|
@ -68,7 +68,12 @@ extern int SOUND_CLOCK_TICKS; // Number of 16.8 MHz clocks between calls to gbSo
|
|||
extern int soundTicks; // Number of 16.8 MHz clocks until gbSoundTick() will be called
|
||||
|
||||
// Saves/loads emulator state
|
||||
#ifdef __LIBRETRO__
|
||||
void gbSoundSaveGame(uint8_t*&);
|
||||
void gbSoundReadGame(const uint8_t*&, int);
|
||||
#else
|
||||
void gbSoundSaveGame(gzFile out);
|
||||
void gbSoundReadGame(int version, gzFile in);
|
||||
#endif
|
||||
|
||||
#endif // GBSOUND_H
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
TILED_RENDERING=0
|
||||
STATIC_LINKING=0
|
||||
FRONTEND_SUPPORTS_RGB565=0
|
||||
FRONTEND_SUPPORTS_RGB565=1
|
||||
|
||||
SPACE :=
|
||||
SPACE := $(SPACE) $(SPACE)
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
INCFLAGS := -I$(CORE_DIR)
|
||||
SOURCES_CXX :=
|
||||
|
||||
SOURCES_CXX := $(CORE_DIR)/gba/GBA-thumb.cpp \
|
||||
SOURCES_CXX += \
|
||||
$(CORE_DIR)/libretro/libretro.cpp \
|
||||
$(CORE_DIR)/libretro/UtilRetro.cpp \
|
||||
$(CORE_DIR)/libretro/SoundRetro.cpp \
|
||||
$(CORE_DIR)/libretro/scrc32.cpp
|
||||
|
||||
SOURCES_CXX += \
|
||||
$(CORE_DIR)/apu/Gb_Oscs.cpp \
|
||||
$(CORE_DIR)/apu/Gb_Apu_State.cpp \
|
||||
$(CORE_DIR)/apu/Blip_Buffer.cpp \
|
||||
$(CORE_DIR)/apu/Multi_Buffer.cpp \
|
||||
$(CORE_DIR)/apu/Effects_Buffer.cpp \
|
||||
$(CORE_DIR)/apu/Gb_Apu.cpp
|
||||
|
||||
SOURCES_CXX += \
|
||||
$(CORE_DIR)/gba/GBA-thumb.cpp \
|
||||
$(CORE_DIR)/gba/Sound.cpp \
|
||||
$(CORE_DIR)/gba/Mode1.cpp \
|
||||
$(CORE_DIR)/gba/CheatSearch.cpp \
|
||||
|
@ -20,13 +36,13 @@ SOURCES_CXX := $(CORE_DIR)/gba/GBA-thumb.cpp \
|
|||
$(CORE_DIR)/gba/GBA.cpp \
|
||||
$(CORE_DIR)/gba/EEprom.cpp \
|
||||
$(CORE_DIR)/gba/RTC.cpp \
|
||||
$(CORE_DIR)/gba/Sram.cpp \
|
||||
$(CORE_DIR)/apu/Gb_Oscs.cpp \
|
||||
$(CORE_DIR)/apu/Gb_Apu_State.cpp \
|
||||
$(CORE_DIR)/apu/Blip_Buffer.cpp \
|
||||
$(CORE_DIR)/apu/Multi_Buffer.cpp \
|
||||
$(CORE_DIR)/apu/Gb_Apu.cpp \
|
||||
$(CORE_DIR)/libretro/libretro.cpp \
|
||||
$(CORE_DIR)/libretro/UtilRetro.cpp \
|
||||
$(CORE_DIR)/libretro/SoundRetro.cpp \
|
||||
$(CORE_DIR)/libretro/scrc32.cpp
|
||||
$(CORE_DIR)/gba/Sram.cpp
|
||||
|
||||
SOURCES_CXX += \
|
||||
$(CORE_DIR)/gb/gbCheats.cpp \
|
||||
$(CORE_DIR)/gb/GB.cpp \
|
||||
$(CORE_DIR)/gb/gbGfx.cpp \
|
||||
$(CORE_DIR)/gb/gbGlobals.cpp \
|
||||
$(CORE_DIR)/gb/gbMemory.cpp \
|
||||
$(CORE_DIR)/gb/gbSGB.cpp \
|
||||
$(CORE_DIR)/gb/gbSound.cpp
|
||||
|
|
|
@ -108,6 +108,7 @@ bool utilIsGBAImage(const char* file)
|
|||
|
||||
bool utilIsGBImage(const char* file)
|
||||
{
|
||||
/*
|
||||
FILE *fp;
|
||||
bool ret = false;
|
||||
char buffer[47];
|
||||
|
@ -121,6 +122,20 @@ bool utilIsGBImage(const char* file)
|
|||
}
|
||||
fclose (fp);
|
||||
return ret;
|
||||
*/
|
||||
if (strlen(file) > 4) {
|
||||
const char *p = strrchr(file, '.');
|
||||
|
||||
if (p != NULL) {
|
||||
if ((_stricmp(p, ".dmg") == 0) || (_stricmp(p, ".gb") == 0)
|
||||
|| (_stricmp(p, ".gbc") == 0) || (_stricmp(p, ".cgb") == 0)
|
||||
|| (_stricmp(p, ".sgb") == 0)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// strip .gz or .z off end
|
||||
|
|
|
@ -25,6 +25,13 @@
|
|||
#include "../gba/Sound.h"
|
||||
#include "../gba/bios.h"
|
||||
|
||||
#include "../gb/gb.h"
|
||||
#include "../gb/gbCheats.h"
|
||||
#include "../gb/gbGlobals.h"
|
||||
#include "../gb/gbMemory.h"
|
||||
#include "../gb/gbSGB.h"
|
||||
#include "../gb/gbSound.h"
|
||||
|
||||
#define RETRO_DEVICE_GBA RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 0)
|
||||
#define RETRO_DEVICE_GBA_ALT1 RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1)
|
||||
#define RETRO_DEVICE_GBA_ALT2 RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 2)
|
||||
|
@ -46,16 +53,21 @@ static bool can_dupe = false;
|
|||
static bool usebios = false;
|
||||
static unsigned retropad_layout = 1;
|
||||
|
||||
static EmulatedSystem* core = NULL;
|
||||
static IMAGE_TYPE type = IMAGE_UNKNOWN;
|
||||
static const double FramesPerSecond = (16777216.0 / 280896.0); // 59.73
|
||||
static const long SampleRate = 32768;
|
||||
static const int GBWidth = 160;
|
||||
static const int GBHeight = 144;
|
||||
static const int SGBWidth = 256;
|
||||
static const int SGBHeight = 224;
|
||||
static const int GBAWidth = 240;
|
||||
static const int GBAHeight = 160;
|
||||
static unsigned width = 240;
|
||||
static unsigned height = 160;
|
||||
static EmulatedSystem* core = NULL;
|
||||
static IMAGE_TYPE type = IMAGE_UNKNOWN;
|
||||
|
||||
uint16_t systemColorMap16[0x10000];
|
||||
uint32_t systemColorMap32[0x10000];
|
||||
uint16_t systemGbPalette[24];
|
||||
int RGB_LOW_BITS_MASK = 0;
|
||||
int systemRedShift = 0;
|
||||
int systemBlueShift = 0;
|
||||
|
@ -71,14 +83,29 @@ int emulating = 0;
|
|||
void (*dbgOutput)(const char* s, uint32_t addr);
|
||||
void (*dbgSignal)(int sig, int number);
|
||||
|
||||
#define GS555(x) (x | (x << 5) | (x << 10))
|
||||
uint16_t systemGbPalette[24] = {
|
||||
GS555(0x1f), GS555(0x15), GS555(0x0c), 0,
|
||||
GS555(0x1f), GS555(0x15), GS555(0x0c), 0,
|
||||
GS555(0x1f), GS555(0x15), GS555(0x0c), 0,
|
||||
GS555(0x1f), GS555(0x15), GS555(0x0c), 0,
|
||||
GS555(0x1f), GS555(0x15), GS555(0x0c), 0,
|
||||
GS555(0x1f), GS555(0x15), GS555(0x0c), 0
|
||||
};
|
||||
|
||||
void* retro_get_memory_data(unsigned id)
|
||||
{
|
||||
if (id == RETRO_MEMORY_SAVE_RAM)
|
||||
{
|
||||
if (type == IMAGE_GBA)
|
||||
{
|
||||
if ((saveType == 1) | (saveType == 4))
|
||||
return eepromData;
|
||||
if ((saveType == 2) | (saveType == 3))
|
||||
return flashSaveMemory;
|
||||
} else {
|
||||
// TODO: GB / GBC saves here
|
||||
}
|
||||
}
|
||||
if (id == RETRO_MEMORY_SYSTEM_RAM)
|
||||
return workRAM;
|
||||
|
@ -91,11 +118,16 @@ void* retro_get_memory_data(unsigned id)
|
|||
size_t retro_get_memory_size(unsigned id)
|
||||
{
|
||||
if (id == RETRO_MEMORY_SAVE_RAM)
|
||||
{
|
||||
if (type == IMAGE_GBA)
|
||||
{
|
||||
if ((saveType == 1) | (saveType == 4))
|
||||
return eepromSize;
|
||||
if ((saveType == 2) | (saveType == 3))
|
||||
return flashSize;
|
||||
} else {
|
||||
// TODO: GB / GBC saves here
|
||||
}
|
||||
}
|
||||
if (id == RETRO_MEMORY_SYSTEM_RAM)
|
||||
return 0x40000;
|
||||
|
@ -207,7 +239,7 @@ void retro_set_environment(retro_environment_t cb)
|
|||
void retro_get_system_info(struct retro_system_info *info)
|
||||
{
|
||||
info->need_fullpath = false;
|
||||
info->valid_extensions = "gba";
|
||||
info->valid_extensions = "dmg|gb|gbc|cgb|sgb|gba";
|
||||
#ifdef GIT_VERSION
|
||||
info->library_version = "2.1.0" GIT_VERSION;
|
||||
#else
|
||||
|
@ -220,6 +252,9 @@ void retro_get_system_info(struct retro_system_info *info)
|
|||
void retro_get_system_av_info(struct retro_system_av_info *info)
|
||||
{
|
||||
float aspect = (3.0f / 2.0f);
|
||||
if (type == IMAGE_GB)
|
||||
aspect = !gbBorderOn ? (10.0 / 9.0) : (8.0 / 7.0);
|
||||
|
||||
info->geometry.base_width = width;
|
||||
info->geometry.base_height = height;
|
||||
info->geometry.max_width = width;
|
||||
|
@ -342,13 +377,7 @@ static void load_image_preferences(void)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static const char SLASH = '\\';
|
||||
#else
|
||||
static const char SLASH = '/';
|
||||
#endif
|
||||
|
||||
static void gba_init(void)
|
||||
static void update_colormaps(void)
|
||||
{
|
||||
#ifdef FRONTEND_SUPPORTS_RGB565
|
||||
systemColorDepth = 16;
|
||||
|
@ -364,8 +393,21 @@ static void gba_init(void)
|
|||
|
||||
utilUpdateSystemColorMaps(false);
|
||||
|
||||
log("Loading VBA-M Core (GBA)...\n");
|
||||
log("Color Depth = %d\n", systemColorDepth);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
static const char SLASH = '\\';
|
||||
#else
|
||||
static const char SLASH = '/';
|
||||
#endif
|
||||
|
||||
static void gba_init(void)
|
||||
{
|
||||
log("Loading VBA-M Core (GBA)...\n");
|
||||
|
||||
update_colormaps();
|
||||
|
||||
load_image_preferences();
|
||||
|
||||
|
@ -397,8 +439,45 @@ static void gba_init(void)
|
|||
|
||||
core = &GBASystem;
|
||||
|
||||
width = 240;
|
||||
height = 160;
|
||||
width = GBAWidth;
|
||||
height = GBAHeight;
|
||||
}
|
||||
|
||||
static void gb_init(void)
|
||||
{
|
||||
const char *biosname[] = {"gb_bios.bin", "gbc_bios.bin"};
|
||||
|
||||
log("Loading VBA-M Core (GB/GBC)...\n");
|
||||
|
||||
update_colormaps();
|
||||
|
||||
soundInit();
|
||||
gbSoundSetSampleRate(SampleRate);
|
||||
|
||||
gbGetHardwareType();
|
||||
|
||||
if (usebios)
|
||||
{
|
||||
snprintf(biosfile, sizeof(biosfile), "%s%c%s",
|
||||
retro_system_directory, SLASH, biosname[gbCgbMode]);
|
||||
log("Loading bios: %s\n", biosfile);
|
||||
}
|
||||
|
||||
gbCPUInit(biosfile, usebios);
|
||||
gbReset();
|
||||
|
||||
if (gbBorderOn) {
|
||||
width = gbBorderLineSkip = SGBWidth;
|
||||
height = SGBHeight;
|
||||
gbBorderColumnSkip = (SGBWidth - GBWidth) >> 1;
|
||||
gbBorderRowSkip = (SGBHeight - GBHeight) >> 1;
|
||||
} else {
|
||||
width = gbBorderLineSkip = GBWidth;
|
||||
height = GBHeight;
|
||||
gbBorderColumnSkip = gbBorderRowSkip = 0;
|
||||
}
|
||||
|
||||
core = &GBSystem;
|
||||
}
|
||||
|
||||
static void gba_soundchanged(void)
|
||||
|
@ -617,10 +696,13 @@ bool retro_unserialize(const void* data, size_t size)
|
|||
}
|
||||
|
||||
void retro_cheat_reset(void)
|
||||
{
|
||||
if (type == IMAGE_GBA)
|
||||
{
|
||||
cheatsEnabled = 1;
|
||||
cheatsDeleteAll(false);
|
||||
}
|
||||
}
|
||||
|
||||
void retro_cheat_set(unsigned index, bool enabled, const char* code)
|
||||
{
|
||||
|
@ -664,6 +746,11 @@ void retro_cheat_set(unsigned index, bool enabled, const char* code)
|
|||
|
||||
} while (*c++);
|
||||
*/
|
||||
|
||||
// TODO: Add cheat code support for GB/GBC
|
||||
if (type != IMAGE_GBA)
|
||||
return;
|
||||
|
||||
std::string codeLine=code;
|
||||
std::string name="cheat_"+index;
|
||||
int matchLength=0;
|
||||
|
@ -785,7 +872,18 @@ bool retro_load_game(const struct retro_game_info *game)
|
|||
update_variables();
|
||||
update_input_descriptors();
|
||||
|
||||
type = utilFindType((const char *)game->path);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case IMAGE_UNKNOWN:
|
||||
log("Unsupported image %s!\n", game->path);
|
||||
return 0;
|
||||
|
||||
case IMAGE_GBA:
|
||||
{
|
||||
romSize = CPULoadRomData((const char*)game->data, game->size);
|
||||
|
||||
if (!romSize)
|
||||
return false;
|
||||
|
||||
|
@ -815,6 +913,17 @@ bool retro_load_game(const struct retro_game_info *game)
|
|||
|
||||
bool yes = true;
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS, &yes);
|
||||
}
|
||||
break;
|
||||
|
||||
case IMAGE_GB:
|
||||
if (!gbLoadRomData((const char *)game->data, game->size))
|
||||
return false;
|
||||
|
||||
gb_init();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t* state_buf = (uint8_t*)malloc(2000000);
|
||||
serialize_size = core->emuWriteState(state_buf, 2000000);
|
||||
|
@ -863,6 +972,19 @@ void systemFrame(void)
|
|||
has_frame = 1;
|
||||
}
|
||||
|
||||
void systemGbBorderOn()
|
||||
{
|
||||
width = gbBorderLineSkip = SGBWidth;
|
||||
height = SGBHeight;
|
||||
gbBorderColumnSkip = (SGBWidth - GBWidth) >> 1;
|
||||
gbBorderRowSkip = (SGBHeight - GBHeight) >> 1;
|
||||
|
||||
struct retro_system_av_info avinfo;
|
||||
retro_get_system_av_info(&avinfo);
|
||||
//environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &avinfo);
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &avinfo);
|
||||
}
|
||||
|
||||
void systemMessage(const char* fmt, ...)
|
||||
{
|
||||
char buffer[256];
|
||||
|
|
Loading…
Reference in New Issue