aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/AREngine.cpp77
-rw-r--r--src/ARMJIT.cpp2
-rw-r--r--src/CP15.cpp6
-rw-r--r--src/Config.cpp4
-rw-r--r--src/Config.h2
-rw-r--r--src/DSi.cpp71
-rw-r--r--src/DSi_NWifi.cpp39
-rw-r--r--src/DSi_NWifi.h4
-rw-r--r--src/GPU.h1
-rw-r--r--src/GPU2D.cpp77
-rw-r--r--src/GPU3D.cpp28
-rw-r--r--src/GPU3D_OpenGL.cpp349
-rw-r--r--src/GPU_OpenGL.cpp7
-rw-r--r--src/NDS.cpp5
-rw-r--r--src/NDS.h2
-rw-r--r--src/SPI.cpp26
-rw-r--r--src/SPI.h1
-rw-r--r--src/SPU.cpp2
-rw-r--r--src/Wifi.cpp9
-rw-r--r--src/frontend/qt_sdl/Platform.cpp4
-rw-r--r--src/frontend/qt_sdl/PlatformConfig.cpp8
-rw-r--r--src/frontend/qt_sdl/PlatformConfig.h2
-rw-r--r--src/frontend/qt_sdl/VideoSettingsDialog.cpp7
-rw-r--r--src/frontend/qt_sdl/VideoSettingsDialog.h1
-rw-r--r--src/frontend/qt_sdl/VideoSettingsDialog.ui12
-rw-r--r--src/frontend/qt_sdl/WifiSettingsDialog.cpp59
-rw-r--r--src/frontend/qt_sdl/WifiSettingsDialog.h7
-rw-r--r--src/frontend/qt_sdl/WifiSettingsDialog.ui12
-rw-r--r--src/frontend/qt_sdl/main.cpp39
29 files changed, 585 insertions, 278 deletions
diff --git a/src/AREngine.cpp b/src/AREngine.cpp
index 8ebf46c..b47bcd4 100644
--- a/src/AREngine.cpp
+++ b/src/AREngine.cpp
@@ -19,6 +19,7 @@
#include <stdio.h>
#include <string.h>
#include "NDS.h"
+#include "DSi.h"
#include "AREngine.h"
@@ -28,6 +29,13 @@ namespace AREngine
// AR code file - frontend is responsible for managing this
ARCodeFile* CodeFile;
+u8 (*BusRead8)(u32 addr);
+u16 (*BusRead16)(u32 addr);
+u32 (*BusRead32)(u32 addr);
+void (*BusWrite8)(u32 addr, u8 val);
+void (*BusWrite16)(u32 addr, u16 val);
+void (*BusWrite32)(u32 addr, u32 val);
+
bool Init()
{
@@ -43,6 +51,25 @@ void DeInit()
void Reset()
{
CodeFile = nullptr;
+
+ if (NDS::ConsoleType == 1)
+ {
+ BusRead8 = DSi::ARM7Read8;
+ BusRead16 = DSi::ARM7Read16;
+ BusRead32 = DSi::ARM7Read32;
+ BusWrite8 = DSi::ARM7Write8;
+ BusWrite16 = DSi::ARM7Write16;
+ BusWrite32 = DSi::ARM7Write32;
+ }
+ else
+ {
+ BusRead8 = NDS::ARM7Read8;
+ BusRead16 = NDS::ARM7Read16;
+ BusRead32 = NDS::ARM7Read32;
+ BusWrite8 = NDS::ARM7Write8;
+ BusWrite16 = NDS::ARM7Write16;
+ BusWrite32 = NDS::ARM7Write32;
+ }
}
@@ -102,15 +129,15 @@ void RunCheat(ARCode& arcode)
switch (op)
{
case16(0x00): // 32-bit write
- NDS::ARM7Write32((a & 0x0FFFFFFF) + offset, b);
+ BusWrite32((a & 0x0FFFFFFF) + offset, b);
break;
case16(0x10): // 16-bit write
- NDS::ARM7Write16((a & 0x0FFFFFFF) + offset, b & 0xFFFF);
+ BusWrite16((a & 0x0FFFFFFF) + offset, b & 0xFFFF);
break;
case16(0x20): // 8-bit write
- NDS::ARM7Write8((a & 0x0FFFFFFF) + offset, b & 0xFF);
+ BusWrite8((a & 0x0FFFFFFF) + offset, b & 0xFF);
break;
case16(0x30): // IF b > u32[a]
@@ -118,7 +145,7 @@ void RunCheat(ARCode& arcode)
condstack <<= 1;
condstack |= cond;
- u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF);
+ u32 chk = BusRead32(a & 0x0FFFFFFF);
cond = (b > chk) ? 1:0;
}
@@ -129,7 +156,7 @@ void RunCheat(ARCode& arcode)
condstack <<= 1;
condstack |= cond;
- u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF);
+ u32 chk = BusRead32(a & 0x0FFFFFFF);
cond = (b < chk) ? 1:0;
}
@@ -140,7 +167,7 @@ void RunCheat(ARCode& arcode)
condstack <<= 1;
condstack |= cond;
- u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF);
+ u32 chk = BusRead32(a & 0x0FFFFFFF);
cond = (b == chk) ? 1:0;
}
@@ -151,7 +178,7 @@ void RunCheat(ARCode& arcode)
condstack <<= 1;
condstack |= cond;
- u32 chk = NDS::ARM7Read32(a & 0x0FFFFFFF);
+ u32 chk = BusRead32(a & 0x0FFFFFFF);
cond = (b != chk) ? 1:0;
}
@@ -162,7 +189,7 @@ void RunCheat(ARCode& arcode)
condstack <<= 1;
condstack |= cond;
- u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF);
+ u16 val = BusRead16(a & 0x0FFFFFFF);
u16 chk = ~(b >> 16);
chk &= val;
@@ -175,7 +202,7 @@ void RunCheat(ARCode& arcode)
condstack <<= 1;
condstack |= cond;
- u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF);
+ u16 val = BusRead16(a & 0x0FFFFFFF);
u16 chk = ~(b >> 16);
chk &= val;
@@ -188,7 +215,7 @@ void RunCheat(ARCode& arcode)
condstack <<= 1;
condstack |= cond;
- u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF);
+ u16 val = BusRead16(a & 0x0FFFFFFF);
u16 chk = ~(b >> 16);
chk &= val;
@@ -201,7 +228,7 @@ void RunCheat(ARCode& arcode)
condstack <<= 1;
condstack |= cond;
- u16 val = NDS::ARM7Read16(a & 0x0FFFFFFF);
+ u16 val = BusRead16(a & 0x0FFFFFFF);
u16 chk = ~(b >> 16);
chk &= val;
@@ -210,7 +237,7 @@ void RunCheat(ARCode& arcode)
break;
case16(0xB0): // offset = u32[a + offset]
- offset = NDS::ARM7Read32((a & 0x0FFFFFFF) + offset);
+ offset = BusRead32((a & 0x0FFFFFFF) + offset);
break;
case 0xC0: // FOR 0..b
@@ -247,7 +274,7 @@ void RunCheat(ARCode& arcode)
break;
case 0xC6: // u32[b] = offset
- NDS::ARM7Write32(b, offset);
+ BusWrite32(b, offset);
break;
case 0xD0: // ENDIF
@@ -296,30 +323,30 @@ void RunCheat(ARCode& arcode)
break;
case 0xD6: // u32[b+offset] = datareg / offset += 4
- NDS::ARM7Write32(b + offset, datareg);
+ BusWrite32(b + offset, datareg);
offset += 4;
break;
case 0xD7: // u16[b+offset] = datareg / offset += 2
- NDS::ARM7Write16(b + offset, datareg & 0xFFFF);
+ BusWrite16(b + offset, datareg & 0xFFFF);
offset += 2;
break;
case 0xD8: // u8[b+offset] = datareg / offset += 1
- NDS::ARM7Write8(b + offset, datareg & 0xFF);
+ BusWrite8(b + offset, datareg & 0xFF);
offset += 1;
break;
case 0xD9: // datareg = u32[b+offset]
- datareg = NDS::ARM7Read32(b + offset);
+ datareg = BusRead32(b + offset);
break;
case 0xDA: // datareg = u16[b+offset]
- datareg = NDS::ARM7Read16(b + offset);
+ datareg = BusRead16(b + offset);
break;
case 0xDB: // datareg = u8[b+offset]
- datareg = NDS::ARM7Read8(b + offset);
+ datareg = BusRead8(b + offset);
break;
case 0xDC: // offset += b
@@ -334,8 +361,8 @@ void RunCheat(ARCode& arcode)
u32 bytesleft = b;
while (bytesleft >= 8)
{
- NDS::ARM7Write32(dstaddr, *code++); dstaddr += 4;
- NDS::ARM7Write32(dstaddr, *code++); dstaddr += 4;
+ BusWrite32(dstaddr, *code++); dstaddr += 4;
+ BusWrite32(dstaddr, *code++); dstaddr += 4;
bytesleft -= 8;
}
if (bytesleft > 0)
@@ -344,13 +371,13 @@ void RunCheat(ARCode& arcode)
code += 2;
if (bytesleft >= 4)
{
- NDS::ARM7Write32(dstaddr, *(u32*)leftover); dstaddr += 4;
+ BusWrite32(dstaddr, *(u32*)leftover); dstaddr += 4;
leftover += 4;
bytesleft -= 4;
}
while (bytesleft > 0)
{
- NDS::ARM7Write8(dstaddr, *leftover++); dstaddr++;
+ BusWrite8(dstaddr, *leftover++); dstaddr++;
bytesleft--;
}
}
@@ -366,14 +393,14 @@ void RunCheat(ARCode& arcode)
u32 bytesleft = b;
while (bytesleft >= 4)
{
- NDS::ARM7Write32(dstaddr, NDS::ARM7Read32(srcaddr));
+ BusWrite32(dstaddr, BusRead32(srcaddr));
srcaddr += 4;
dstaddr += 4;
bytesleft -= 4;
}
while (bytesleft > 0)
{
- NDS::ARM7Write8(dstaddr, NDS::ARM7Read8(srcaddr));
+ BusWrite8(dstaddr, BusRead8(srcaddr));
srcaddr++;
dstaddr++;
bytesleft--;
diff --git a/src/ARMJIT.cpp b/src/ARMJIT.cpp
index 59f7f54..31983f6 100644
--- a/src/ARMJIT.cpp
+++ b/src/ARMJIT.cpp
@@ -480,7 +480,7 @@ InterpreterFunc InterpretARM[ARMInstrInfo::ak_Count] =
F_ALU(CMN,),
F(MUL), F(MLA), F(UMULL), F(UMLAL), F(SMULL), F(SMLAL), F(SMLAxy), F(SMLAWy), F(SMULWy), F(SMLALxy), F(SMULxy),
- F(CLZ), F(QADD), F(QDADD), F(QSUB), F(QDSUB),
+ F(CLZ), F(QADD), F(QSUB), F(QDADD), F(QDSUB),
F_MEM_WB(STR),
F_MEM_WB(STRB),
diff --git a/src/CP15.cpp b/src/CP15.cpp
index f6476ab..3f9e79d 100644
--- a/src/CP15.cpp
+++ b/src/CP15.cpp
@@ -616,11 +616,11 @@ void ARMv5::CP15Write(u32 id, u32 val)
case 0xF00:
//printf("cache debug index register %08X\n", val);
return;
-
+
case 0xF10:
//printf("cache debug instruction tag %08X\n", val);
return;
-
+
case 0xF20:
//printf("cache debug data tag %08X\n", val);
return;
@@ -632,7 +632,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
case 0xF40:
//printf("cache debug data cache %08X\n", val);
return;
-
+
}
if ((id & 0xF00) == 0xF00) // test/debug shit?
diff --git a/src/Config.cpp b/src/Config.cpp
index d198093..949c1bf 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -37,6 +37,8 @@ char DSiBIOS7Path[1024];
char DSiFirmwarePath[1024];
char DSiNANDPath[1024];
+int RandomizeMAC;
+
#ifdef JIT_ENABLED
int JIT_Enable = false;
int JIT_MaxBlockSize = 32;
@@ -56,6 +58,8 @@ ConfigEntry ConfigFile[] =
{"DSiFirmwarePath", 1, DSiFirmwarePath, 0, "", 1023},
{"DSiNANDPath", 1, DSiNANDPath, 0, "", 1023},
+ {"RandomizeMAC", 0, &RandomizeMAC, 0, NULL, 0},
+
#ifdef JIT_ENABLED
{"JIT_Enable", 0, &JIT_Enable, 0, NULL, 0},
{"JIT_MaxBlockSize", 0, &JIT_MaxBlockSize, 32, NULL, 0},
diff --git a/src/Config.h b/src/Config.h
index 5916b4a..a0f09dc 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -51,6 +51,8 @@ extern char DSiBIOS7Path[1024];
extern char DSiFirmwarePath[1024];
extern char DSiNANDPath[1024];
+extern int RandomizeMAC;
+
#ifdef JIT_ENABLED
extern int JIT_Enable;
extern int JIT_MaxBlockSize;
diff --git a/src/DSi.cpp b/src/DSi.cpp
index 42541fe..66b8ed0 100644
--- a/src/DSi.cpp
+++ b/src/DSi.cpp
@@ -699,20 +699,37 @@ void MapNWRAMRange(u32 cpu, u32 num, u32 val)
}
}
+void ApplyNewRAMSize(u32 size)
+{
+ switch (size)
+ {
+ case 0:
+ case 1:
+ NDS::MainRAMMask = 0x3FFFFF;
+ printf("RAM: 4MB\n");
+ break;
+ case 2:
+ case 3: // TODO: debug console w/ 32MB?
+ NDS::MainRAMMask = 0xFFFFFF;
+ printf("RAM: 16MB\n");
+ break;
+ }
+}
+
void Set_SCFG_Clock9(u16 val)
{
- SCFG_Clock9 = val & 0x0187;
- return;
-
NDS::ARM9Timestamp >>= NDS::ARM9ClockShift;
+ NDS::ARM9Target >>= NDS::ARM9ClockShift;
printf("CLOCK9=%04X\n", val);
SCFG_Clock9 = val & 0x0187;
if (SCFG_Clock9 & (1<<0)) NDS::ARM9ClockShift = 2;
else NDS::ARM9ClockShift = 1;
+
NDS::ARM9Timestamp <<= NDS::ARM9ClockShift;
+ NDS::ARM9Target <<= NDS::ARM9ClockShift;
NDS::ARM9->UpdateRegionTimings(0x00000000, 0xFFFFFFFF);
}
@@ -1549,25 +1566,37 @@ void ARM9IOWrite32(u32 addr, u32 val)
switch (addr)
{
case 0x04004008:
- SCFG_EXT[0] &= ~0x8007F19F;
- SCFG_EXT[0] |= (val & 0x8007F19F);
- SCFG_EXT[1] &= ~0x0000F080;
- SCFG_EXT[1] |= (val & 0x0000F080);
- printf("SCFG_EXT = %08X / %08X (val9 %08X)\n", SCFG_EXT[0], SCFG_EXT[1], val);
- /*switch ((SCFG_EXT[0] >> 14) & 0x3)
{
- case 0:
- case 1:
- NDS::MainRAMMask = 0x3FFFFF;
- printf("RAM: 4MB\n");
- break;
- case 2:
- case 3: // TODO: debug console w/ 32MB?
- NDS::MainRAMMask = 0xFFFFFF;
- printf("RAM: 16MB\n");
- break;
- }*/
- printf("from %08X, ARM7 %08X, %08X\n", NDS::GetPC(0), NDS::GetPC(1), NDS::ARM7->R[1]);
+ u32 oldram = (SCFG_EXT[0] >> 14) & 0x3;
+ u32 newram = (val >> 14) & 0x3;
+
+ SCFG_EXT[0] &= ~0x8007F19F;
+ SCFG_EXT[0] |= (val & 0x8007F19F);
+ SCFG_EXT[1] &= ~0x0000F080;
+ SCFG_EXT[1] |= (val & 0x0000F080);
+ printf("SCFG_EXT = %08X / %08X (val9 %08X)\n", SCFG_EXT[0], SCFG_EXT[1], val);
+ /*switch ((SCFG_EXT[0] >> 14) & 0x3)
+ {
+ case 0:
+ case 1:
+ NDS::MainRAMMask = 0x3FFFFF;
+ printf("RAM: 4MB\n");
+ //baziderp=true;
+ break;
+ case 2:
+ case 3: // TODO: debug console w/ 32MB?
+ NDS::MainRAMMask = 0xFFFFFF;
+ printf("RAM: 16MB\n");
+ break;
+ }*/
+ // HAX!!
+ // a change to the RAM size setting is supposed to apply immediately (it does so on hardware)
+ // however, doing so will cause DS-mode app startup to break, because the change happens while the ARM7
+ // is still busy clearing/relocating shit
+ //if (newram != oldram)
+ // NDS::ScheduleEvent(NDS::Event_DSi_RAMSizeChange, false, 512*512*512, ApplyNewRAMSize, newram);
+ printf("from %08X, ARM7 %08X, %08X\n", NDS::GetPC(0), NDS::GetPC(1), NDS::ARM7->R[1]);
+ }
return;
case 0x04004040:
diff --git a/src/DSi_NWifi.cpp b/src/DSi_NWifi.cpp
index 73cf4b4..54719cf 100644
--- a/src/DSi_NWifi.cpp
+++ b/src/DSi_NWifi.cpp
@@ -165,6 +165,36 @@ void DSi_NWifi::Reset()
printf("NWifi MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ u8 type = SPI_Firmware::GetNWifiVersion();
+ switch (type)
+ {
+ case 1: // AR6002
+ ROMID = 0x20000188;
+ ChipID = 0x02000001;
+ HostIntAddr = 0x00500400;
+ break;
+
+ case 2: // AR6013
+ ROMID = 0x23000024;
+ ChipID = 0x0D000000;
+ HostIntAddr = 0x00520000;
+ break;
+
+ case 3: // AR6014 (3DS)
+ ROMID = 0x2300006F;
+ ChipID = 0x0D000001;
+ HostIntAddr = 0x00520000;
+ printf("NWifi: hardware is 3DS type, unchecked\n");
+ break;
+
+ default:
+ printf("NWifi: unknown hardware type %02X, assuming AR6002\n");
+ ROMID = 0x20000188;
+ ChipID = 0x02000001;
+ HostIntAddr = 0x00500400;
+ break;
+ }
+
memset(EEPROM, 0, 0x400);
*(u32*)&EEPROM[0x000] = 0x300;
@@ -755,8 +785,7 @@ void DSi_NWifi::BMI_Command()
case 0x08: // BMI_GET_TARGET_ID
MB_Write32(4, 0xFFFFFFFF);
MB_Write32(4, 0x0000000C);
- //MB_Write32(4, 0x20000118);
- MB_Write32(4, 0x23000024); // ROM version (TODO: how to determine correct one?)
+ MB_Write32(4, ROMID);
MB_Write32(4, 0x00000002);
return;
@@ -1436,7 +1465,7 @@ u32 DSi_NWifi::WindowRead(u32 addr)
{
printf("NWifi: window read %08X\n", addr);
- if ((addr & 0xFFFF00) == 0x520000)
+ if ((addr & 0xFFFF00) == HostIntAddr)
{
// RAM host interest area
// TODO: different base based on hardware version
@@ -1462,9 +1491,7 @@ u32 DSi_NWifi::WindowRead(u32 addr)
switch (addr)
{
case 0x40EC: // chip ID
- // 0D000000 / 0D000001 == AR6013
- // TODO: check firmware.bin to determine the correct value
- return 0x0D000001;
+ return ChipID;
// SOC_RESET_CAUSE
case 0x40C0: return 2;
diff --git a/src/DSi_NWifi.h b/src/DSi_NWifi.h
index a72d54d..7efd40c 100644
--- a/src/DSi_NWifi.h
+++ b/src/DSi_NWifi.h
@@ -127,6 +127,10 @@ private:
u32 WindowData, WindowReadAddr, WindowWriteAddr;
+ u32 ROMID;
+ u32 ChipID;
+ u32 HostIntAddr;
+
u8 EEPROM[0x400];
u32 EEPROMReady;
diff --git a/src/GPU.h b/src/GPU.h
index 039e065..c7d25ec 100644
--- a/src/GPU.h
+++ b/src/GPU.h
@@ -79,6 +79,7 @@ typedef struct
bool Soft_Threaded;
int GL_ScaleFactor;
+ bool GL_BetterPolygons;
} RenderSettings;
diff --git a/src/GPU2D.cpp b/src/GPU2D.cpp
index 604a4ee..2c3086c 100644
--- a/src/GPU2D.cpp
+++ b/src/GPU2D.cpp
@@ -35,9 +35,6 @@
// * [Gericom] bit15 is used as bottom green bit for palettes. TODO: check where this applies.
// tested on the normal BG palette and applies there
//
-// oh also, changing DISPCNT bit16-17 midframe doesn't work (ignored? applied for next frame?)
-// TODO, eventually: check whether other DISPCNT bits can be changed midframe
-//
// for VRAM display mode, VRAM must be mapped to LCDC
//
// FIFO display mode:
@@ -78,7 +75,10 @@
// * for rotscaled sprites: coordinates that are inside the sprite are clamped to the sprite region
// after being transformed for mosaic
-// TODO: find which parts of DISPCNT are latched. for example, not possible to change video mode midframe.
+// TODO: master brightness, display capture and mainmem FIFO are separate circuitry, distinct from
+// the tile renderers.
+// for example these aren't affected by POWCNT GPU-disable bits.
+// to model the hardware more accurately, the relevant logic should be moved to GPU.cpp.
GPU2D::GPU2D(u32 num)
@@ -309,8 +309,6 @@ u32 GPU2D::Read32(u32 addr)
void GPU2D::Write8(u32 addr, u8 val)
{
- if (!Enabled) return;
-
switch (addr & 0x00000FFF)
{
case 0x000:
@@ -329,7 +327,12 @@ void GPU2D::Write8(u32 addr, u8 val)
DispCnt = (DispCnt & 0x00FFFFFF) | (val << 24);
if (Num) DispCnt &= 0xC0B1FFF7;
return;
+ }
+ if (!Enabled) return;
+
+ switch (addr & 0x00000FFF)
+ {
case 0x008: BGCnt[0] = (BGCnt[0] & 0xFF00) | val; return;
case 0x009: BGCnt[0] = (BGCnt[0] & 0x00FF) | (val << 8); return;
case 0x00A: BGCnt[1] = (BGCnt[1] & 0xFF00) | val; return;
@@ -405,8 +408,6 @@ void GPU2D::Write8(u32 addr, u8 val)
void GPU2D::Write16(u32 addr, u16 val)
{
- if (!Enabled) return;
-
switch (addr & 0x00000FFF)
{
case 0x000:
@@ -418,6 +419,22 @@ void GPU2D::Write16(u32 addr, u16 val)
if (Num) DispCnt &= 0xC0B1FFF7;
return;
+ case 0x068:
+ DispFIFO[DispFIFOWritePtr] = val;
+ return;
+ case 0x06A:
+ DispFIFO[DispFIFOWritePtr+1] = val;
+ DispFIFOWritePtr += 2;
+ DispFIFOWritePtr &= 0xF;
+ return;
+
+ case 0x06C: MasterBrightness = val; return;
+ }
+
+ if (!Enabled) return;
+
+ switch (addr & 0x00000FFF)
+ {
case 0x008: BGCnt[0] = val; return;
case 0x00A: BGCnt[1] = val; return;
case 0x00C: BGCnt[2] = val; return;
@@ -526,17 +543,6 @@ void GPU2D::Write16(u32 addr, u16 val)
EVY = val & 0x1F;
if (EVY > 16) EVY = 16;
return;
-
- case 0x068:
- DispFIFO[DispFIFOWritePtr] = val;
- return;
- case 0x06A:
- DispFIFO[DispFIFOWritePtr+1] = val;
- DispFIFOWritePtr += 2;
- DispFIFOWritePtr &= 0xF;
- return;
-
- case 0x06C: MasterBrightness = val; return;
}
//printf("unknown GPU write16 %08X %04X\n", addr, val);
@@ -544,8 +550,6 @@ void GPU2D::Write16(u32 addr, u16 val)
void GPU2D::Write32(u32 addr, u32 val)
{
- if (!Enabled) return;
-
switch (addr & 0x00000FFF)
{
case 0x000:
@@ -553,6 +557,24 @@ void GPU2D::Write32(u32 addr, u32 val)
if (Num) DispCnt &= 0xC0B1FFF7;
return;
+ case 0x064:
+ // TODO: check what happens when writing to it during display
+ // esp. if a capture is happening
+ CaptureCnt = val & 0xEF3F1F1F;
+ return;
+
+ case 0x068:
+ DispFIFO[DispFIFOWritePtr] = val & 0xFFFF;
+ DispFIFO[DispFIFOWritePtr+1] = val >> 16;
+ DispFIFOWritePtr += 2;
+ DispFIFOWritePtr &= 0xF;
+ return;
+ }
+
+ if (!Enabled) return;
+
+ switch (addr & 0x00000FFF)
+ {
case 0x028:
if (val & 0x08000000) val |= 0xF0000000;
BGXRef[0] = val;
@@ -574,19 +596,6 @@ void GPU2D::Write32(u32 addr, u32 val)
BGYRef[1] = val;
if (GPU::VCount < 192) BGYRefInternal[1] = BGYRef[1];
return;
-
- case 0x064:
- // TODO: check what happens when writing to it during display
- // esp. if a capture is happening
- CaptureCnt = val & 0xEF3F1F1F;
- return;
-
- case 0x068:
- DispFIFO[DispFIFOWritePtr] = val & 0xFFFF;
- DispFIFO[DispFIFOWritePtr+1] = val >> 16;
- DispFIFOWritePtr += 2;
- DispFIFOWritePtr &= 0xF;
- return;
}
Write16(addr, val&0xFFFF);
diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp
index bd27783..d9d6ba8 100644
--- a/src/GPU3D.cpp
+++ b/src/GPU3D.cpp
@@ -401,8 +401,33 @@ void DoSavestate(Savestate* file)
file->Var32(&NumTestCommands);
file->Var32(&DispCnt);
+ file->Var8(&AlphaRefVal);
file->Var8(&AlphaRef);
+ file->VarArray(ToonTable, 32*2);
+ file->VarArray(EdgeTable, 8*2);
+
+ file->Var32(&FogColor);
+ file->Var32(&FogOffset);
+ file->VarArray(FogDensityTable, 32);
+
+ file->Var32(&ClearAttr1);
+ file->Var32(&ClearAttr2);
+
+ file->Var32(&RenderDispCnt);
+ file->Var8(&RenderAlphaRef);
+
+ file->VarArray(RenderToonTable, 32*2);
+ file->VarArray(RenderEdgeTable, 8*2);
+
+ file->Var32(&RenderFogColor);
+ file->Var32(&RenderFogOffset);
+ file->Var32(&RenderFogShift);
+ file->VarArray(RenderFogDensityTable, 34);
+
+ file->Var32(&RenderClearAttr1);
+ file->Var32(&RenderClearAttr2);
+
file->Var32(&ZeroDotWLimit);
file->Var32(&GXStat);
@@ -471,9 +496,6 @@ void DoSavestate(Savestate* file)
file->Var32(&NumPolygons);
file->Var32(&NumOpaquePolygons);
- file->Var32(&ClearAttr1);
- file->Var32(&ClearAttr2);
-
file->Var32(&FlushRequest);
file->Var32(&FlushAttributes);
diff --git a/src/GPU3D_OpenGL.cpp b/src/GPU3D_OpenGL.cpp
index 8a06874..658b261 100644
--- a/src/GPU3D_OpenGL.cpp
+++ b/src/GPU3D_OpenGL.cpp
@@ -113,7 +113,7 @@ GLuint TexMemID;
GLuint TexPalMemID;
int ScaleFactor;
-bool Antialias;
+bool BetterPolygons;
int ScreenW, ScreenH;
GLuint FramebufferTex[8];
@@ -342,9 +342,6 @@ bool Init()
SetupDefaultTexParams(FramebufferTex[5]);
SetupDefaultTexParams(FramebufferTex[7]);
- // downscale framebuffer for antialiased mode
- SetupDefaultTexParams(FramebufferTex[2]);
-
// downscale framebuffer for display capture (always 256x192)
SetupDefaultTexParams(FramebufferTex[3]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 192, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
@@ -372,6 +369,8 @@ bool Init()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 1024, 48, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
return true;
}
@@ -404,52 +403,27 @@ void Reset()
void SetRenderSettings(GPU::RenderSettings& settings)
{
int scale = settings.GL_ScaleFactor;
- bool antialias = false; // REMOVE ME!
-
- if (antialias) scale *= 2;
ScaleFactor = scale;
- Antialias = antialias;
+ BetterPolygons = settings.GL_BetterPolygons;
ScreenW = 256 * scale;
ScreenH = 192 * scale;
- if (!antialias)
- {
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[0]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[1]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[2]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[4]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, ScreenW, ScreenH, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
- //glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH32F_STENCIL8, ScreenW, ScreenH, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, NULL);
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[5]);
- //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8UI, ScreenW, ScreenH, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, NULL);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ScreenW, ScreenH, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[6]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, 1, 1, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[7]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8UI, 1, 1, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, NULL);
- }
- else
- {
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[0]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW/2, ScreenH/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[1]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW/2, ScreenH/2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[2]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[4]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, ScreenW/2, ScreenH/2, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[5]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8UI, ScreenW/2, ScreenH/2, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, NULL);
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[6]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, ScreenW, ScreenH, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[7]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8UI, ScreenW, ScreenH, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, NULL);
- }
+ glBindTexture(GL_TEXTURE_2D, FramebufferTex[0]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, FramebufferTex[1]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+ glBindTexture(GL_TEXTURE_2D, FramebufferTex[4]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, ScreenW, ScreenH, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
+ glBindTexture(GL_TEXTURE_2D, FramebufferTex[5]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ScreenW, ScreenH, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+
+ glBindTexture(GL_TEXTURE_2D, FramebufferTex[6]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, ScreenW, ScreenH, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
+ glBindTexture(GL_TEXTURE_2D, FramebufferTex[7]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ScreenW, ScreenH, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[3]);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FramebufferTex[3], 0);
@@ -464,12 +438,6 @@ void SetRenderSettings(GPU::RenderSettings& settings)
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[1]);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FramebufferTex[1], 0);
- glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, FramebufferTex[4], 0);
- glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, FramebufferTex[5], 0);
- glDrawBuffers(2, fbassign);
-
- glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[2]);
- glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FramebufferTex[2], 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, FramebufferTex[6], 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, FramebufferTex[7], 0);
glDrawBuffers(2, fbassign);
@@ -479,6 +447,8 @@ void SetRenderSettings(GPU::RenderSettings& settings)
glBindBuffer(GL_PIXEL_PACK_BUFFER, PixelbufferID);
glBufferData(GL_PIXEL_PACK_BUFFER, 256*192*4, NULL, GL_DYNAMIC_READ);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
//glLineWidth(scale);
//glLineWidth(1.5);
}
@@ -527,6 +497,67 @@ void SetupPolygon(RendererPolygon* rp, Polygon* polygon)
}
}
+u32* SetupVertex(Polygon* poly, int vid, Vertex* vtx, u32 vtxattr, u32* vptr)
+{
+ u32 z = poly->FinalZ[vid];
+ u32 w = poly->FinalW[vid];
+
+ u32 alpha = (poly->Attr >> 16) & 0x1F;
+
+ // Z should always fit within 16 bits, so it's okay to do this
+ u32 zshift = 0;
+ while (z > 0xFFFF) { z >>= 1; zshift++; }
+
+ u32 x, y;
+ if (ScaleFactor > 1)
+ {
+ x = (vtx->HiresPosition[0] * ScaleFactor) >> 4;
+ y = (vtx->HiresPosition[1] * ScaleFactor) >> 4;
+ }
+ else
+ {
+ x = vtx->FinalPosition[0];
+ y = vtx->FinalPosition[1];
+ }
+
+ // correct nearly-vertical edges that would look vertical on the DS
+ /*{
+ int vtopid = vid - 1;
+ if (vtopid < 0) vtopid = poly->NumVertices-1;
+ Vertex* vtop = poly->Vertices[vtopid];
+ if (vtop->FinalPosition[1] >= vtx->FinalPosition[1])
+ {
+ vtopid = vid + 1;
+ if (vtopid >= poly->NumVertices) vtopid = 0;
+ vtop = poly->Vertices[vtopid];
+ }
+ if ((vtop->FinalPosition[1] < vtx->FinalPosition[1]) &&
+ (vtx->FinalPosition[0] == vtop->FinalPosition[0]-1))
+ {
+ if (ScaleFactor > 1)
+ x = (vtop->HiresPosition[0] * ScaleFactor) >> 4;
+ else
+ x = vtop->FinalPosition[0];
+ }
+ }*/
+
+ *vptr++ = x | (y << 16);
+ *vptr++ = z | (w << 16);
+
+ *vptr++ = (vtx->FinalColor[0] >> 1) |
+ ((vtx->FinalColor[1] >> 1) << 8) |
+ ((vtx->FinalColor[2] >> 1) << 16) |
+ (alpha << 24);
+
+ *vptr++ = (u16)vtx->TexCoords[0] | ((u16)vtx->TexCoords[1] << 16);
+
+ *vptr++ = vtxattr | (zshift << 16);
+ *vptr++ = poly->TexParam;
+ *vptr++ = poly->TexPalette;
+
+ return vptr;
+}
+
void BuildPolygons(RendererPolygon* polygons, int npolys)
{
u32* vptr = &VertexBuffer[0];
@@ -564,43 +595,16 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
{
Vertex* vtx = poly->Vertices[j];
- u32 z = poly->FinalZ[j];
- u32 w = poly->FinalW[j];
-
- // Z should always fit within 16 bits, so it's okay to do this
- u32 zshift = 0;
- while (z > 0xFFFF) { z >>= 1; zshift++; }
-
- u32 x, y;
- if (ScaleFactor > 1)
- {
- x = (vtx->HiresPosition[0] * ScaleFactor) >> 4;
- y = (vtx->HiresPosition[1] * ScaleFactor) >> 4;
- }
- else
- {
- x = vtx->FinalPosition[0];
- y = vtx->FinalPosition[1];
- }
-
if (j > 0)
{
- if (lastx == x && lasty == y) continue;
+ if (lastx == vtx->FinalPosition[0] &&
+ lasty == vtx->FinalPosition[1]) continue;
}
- *vptr++ = x | (y << 16);
- *vptr++ = z | (w << 16);
+ lastx = vtx->FinalPosition[0];
+ lasty = vtx->FinalPosition[1];
- *vptr++ = (vtx->FinalColor[0] >> 1) |
- ((vtx->FinalColor[1] >> 1) << 8) |
- ((vtx->FinalColor[2] >> 1) << 16) |
- (alpha << 24);
-
- *vptr++ = (u16)vtx->TexCoords[0] | ((u16)vtx->TexCoords[1] << 16);
-
- *vptr++ = vtxattr | (zshift << 16);
- *vptr++ = poly->TexParam;
- *vptr++ = poly->TexPalette;
+ vptr = SetupVertex(poly, j, vtx, vtxattr, vptr);
*iptr++ = vidx;
rp->NumIndices++;
@@ -610,57 +614,148 @@ void BuildPolygons(RendererPolygon* polygons, int npolys)
if (nout >= 2) break;
}
}
- else
+ else if (poly->NumVertices == 3) // regular triangle
{
rp->PrimType = GL_TRIANGLES;
- for (int j = 0; j < poly->NumVertices; j++)
+ for (int j = 0; j < 3; j++)
{
Vertex* vtx = poly->Vertices[j];
- u32 z = poly->FinalZ[j];
- u32 w = poly->FinalW[j];
+ vptr = SetupVertex(poly, j, vtx, vtxattr, vptr);
+ vidx++;
+ }
- // Z should always fit within 16 bits, so it's okay to do this
- u32 zshift = 0;
- while (z > 0xFFFF) { z >>= 1; zshift++; }
+ // build a triangle
+ *iptr++ = vidx_first;
+ *iptr++ = vidx - 2;
+ *iptr++ = vidx - 1;
+ rp->NumIndices += 3;
+ }
+ else // quad, pentagon, etc
+ {
+ rp->PrimType = GL_TRIANGLES;
+
+ if (!BetterPolygons)
+ {
+ // regular triangle-splitting
- u32 x, y;
- if (ScaleFactor > 1)
+ for (int j = 0; j < poly->NumVertices; j++)
{
- x = (vtx->HiresPosition[0] * ScaleFactor) >> 4;
- y = (vtx->HiresPosition[1] * ScaleFactor) >> 4;
+ Vertex* vtx = poly->Vertices[j];
+
+ vptr = SetupVertex(poly, j, vtx, vtxattr, vptr);
+
+ if (j >= 2)
+ {
+ // build a triangle
+ *iptr++ = vidx_first;
+ *iptr++ = vidx - 1;
+ *iptr++ = vidx;
+ rp->NumIndices += 3;
+ }
+
+ vidx++;
}
- else
+ }
+ else
+ {
+ // attempt at 'better' splitting
+ // this doesn't get rid of the error while splitting a bigger polygon into triangles
+ // but we can attempt to reduce it
+
+ u32 cX = 0, cY = 0;
+ float cZ = 0;
+ float cW = 0;
+
+ float cR = 0, cG = 0, cB = 0;
+ float cS = 0, cT = 0;
+
+ for (int j = 0; j < poly->NumVertices; j++)
{
- x = vtx->FinalPosition[0];
- y = vtx->FinalPosition[1];
+ Vertex* vtx = poly->Vertices[j];
+
+ cX += vtx->HiresPosition[0];
+ cY += vtx->HiresPosition[1];
+
+ float fw = (float)poly->FinalW[j] * poly->NumVertices;
+ cW += 1.0f / fw;
+
+ if (poly->WBuffer) cZ += poly->FinalZ[j] / fw;
+ else cZ += poly->FinalZ[j];
+
+ cR += (vtx->FinalColor[0] >> 1) / fw;
+ cG += (vtx->FinalColor[1] >> 1) / fw;
+ cB += (vtx->FinalColor[2] >> 1) / fw;
+
+ cS += vtx->TexCoords[0] / fw;
+ cT += vtx->TexCoords[1] / fw;
}
- *vptr++ = x | (y << 16);
+ cX /= poly->NumVertices;
+ cY /= poly->NumVertices;
+
+ cW = 1.0f / cW;
+
+ if (poly->WBuffer) cZ *= cW;
+ else cZ /= poly->NumVertices;
+
+ cR *= cW;
+ cG *= cW;
+ cB *= cW;
+
+ cS *= cW;
+ cT *= cW;
+
+ cX = (cX * ScaleFactor) >> 4;
+ cY = (cY * ScaleFactor) >> 4;
+
+ u32 w = (u32)cW;
+
+ u32 z = (u32)cZ;
+ u32 zshift = 0;
+ while (z > 0xFFFF) { z >>= 1; zshift++; }
+
+ // build center vertex
+ *vptr++ = cX | (cY << 16);
*vptr++ = z | (w << 16);
- *vptr++ = (vtx->FinalColor[0] >> 1) |
- ((vtx->FinalColor[1] >> 1) << 8) |
- ((vtx->FinalColor[2] >> 1) << 16) |
+ *vptr++ = (u32)cR |
+ ((u32)cG << 8) |
+ ((u32)cB << 16) |
(alpha << 24);
- *vptr++ = (u16)vtx->TexCoords[0] | ((u16)vtx->TexCoords[1] << 16);
+ *vptr++ = (u16)cS | ((u16)cT << 16);
*vptr++ = vtxattr | (zshift << 16);
*vptr++ = poly->TexParam;
*vptr++ = poly->TexPalette;
- if (j >= 2)
+ vidx++;
+
+ // build the final polygon
+ for (int j = 0; j < poly->NumVertices; j++)
{
- // build a triangle
- *iptr++ = vidx_first;
- *iptr++ = vidx - 1;
- *iptr++ = vidx;
- rp->NumIndices += 3;
+ Vertex* vtx = poly->Vertices[j];
+
+ vptr = SetupVertex(poly, j, vtx, vtxattr, vptr);
+
+ if (j >= 1)
+ {
+ // build a triangle
+ *iptr++ = vidx_first;
+ *iptr++ = vidx - 1;
+ *iptr++ = vidx;
+ rp->NumIndices += 3;
+ }
+
+ vidx++;
}
- vidx++;
+ *iptr++ = vidx_first;
+ *iptr++ = vidx - 1;
+ *iptr++ = vidx_first + 1;
+ rp->NumIndices += 3;
}
}
@@ -741,6 +836,10 @@ void RenderSceneChunk(int y, int h)
GLboolean fogenable = (RenderDispCnt & (1<<7)) ? GL_TRUE : GL_FALSE;
+ // TODO: proper 'equal' depth test!
+ // (has margin of +-0x200 in Z-buffer mode, +-0xFF in W-buffer mode)
+ // for now we're using GL_LEQUAL to make it work to some extent
+
// pass 1: opaque pixels
UseRenderShader(flags);
@@ -759,8 +858,10 @@ void RenderSceneChunk(int y, int h)
if (rp->PolyData->IsShadowMask) { i++; continue; }
- // zorp
- glDepthFunc(GL_LESS);
+ if (rp->PolyData->Attr & (1<<14))
+ glDepthFunc(GL_LEQUAL);
+ else
+ glDepthFunc(GL_LESS);
u32 polyattr = rp->PolyData->Attr;
u32 polyid = (polyattr >> 24) & 0x3F;
@@ -845,8 +946,10 @@ void RenderSceneChunk(int y, int h)
{
UseRenderShader(flags | RenderFlag_Trans);
- // zorp
- glDepthFunc(GL_LESS);
+ if (rp->PolyData->Attr & (1<<14))
+ glDepthFunc(GL_LEQUAL);
+ else
+ glDepthFunc(GL_LESS);
u32 polyattr = rp->PolyData->Attr;
u32 polyid = (polyattr >> 24) & 0x3F;
@@ -936,8 +1039,10 @@ void RenderSceneChunk(int y, int h)
if (!(polyattr & (1<<15))) transfog = fogenable;
else transfog = GL_FALSE;
- // zorp
- glDepthFunc(GL_LESS);
+ if (rp->PolyData->Attr & (1<<14))
+ glDepthFunc(GL_LEQUAL);
+ else
+ glDepthFunc(GL_LESS);
if (rp->PolyData->IsShadow)
{
@@ -1003,9 +1108,9 @@ void RenderSceneChunk(int y, int h)
glStencilMask(0);
glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[4]);
+ glBindTexture(GL_TEXTURE_2D, FramebufferTex[FrontBuffer ? 6 : 4]);
glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, FramebufferTex[5]);
+ glBindTexture(GL_TEXTURE_2D, FramebufferTex[FrontBuffer ? 7 : 5]);
glBindBuffer(GL_ARRAY_BUFFER, ClearVertexBufferID);
glBindVertexArray(ClearVertexArrayID);
@@ -1055,8 +1160,8 @@ void RenderFrame()
{
CurShaderID = -1;
- if (Antialias) glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[2]);
- else glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[FrontBuffer]);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferID[FrontBuffer]);
ShaderConfig.uScreenSize[0] = ScreenW;
ShaderConfig.uScreenSize[1] = ScreenH;
@@ -1218,14 +1323,6 @@ void RenderFrame()
RenderSceneChunk(0, 192);
}
- if (Antialias)
- {
- glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferID[2]);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferID[FrontBuffer]);
- glBlitFramebuffer(0, 0, ScreenW, ScreenH, 0, 0, ScreenW/2, ScreenH/2, GL_COLOR_BUFFER_BIT, GL_LINEAR);
- }
-
- //glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[FrontBuffer]);
FrontBuffer = FrontBuffer ? 0 : 1;
}
diff --git a/src/GPU_OpenGL.cpp b/src/GPU_OpenGL.cpp
index 1cb6864..359e9cd 100644
--- a/src/GPU_OpenGL.cpp
+++ b/src/GPU_OpenGL.cpp
@@ -121,6 +121,8 @@ bool Init()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
return true;
}
@@ -157,12 +159,15 @@ void SetRenderSettings(RenderSettings& settings)
glBindFramebuffer(GL_FRAMEBUFFER, CompScreenOutputFB);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, CompScreenOutputTex, 0);
glDrawBuffers(1, fbassign);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void RenderFrame()
{
- glBindFramebuffer(GL_FRAMEBUFFER, CompScreenOutputFB);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, CompScreenOutputFB);
glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
diff --git a/src/NDS.cpp b/src/NDS.cpp
index 823d39a..bb579f6 100644
--- a/src/NDS.cpp
+++ b/src/NDS.cpp
@@ -1817,15 +1817,16 @@ void debug(u32 param)
fwrite(&val, 4, 1, shit);
}
fclose(shit);*/
+
FILE*
- shit = fopen("debug/dump9.bin", "wb");
+ shit = fopen("debug/picto9.bin", "wb");
for (u32 i = 0x02000000; i < 0x04000000; i+=4)
{
u32 val = DSi::ARM9Read32(i);
fwrite(&val, 4, 1, shit);
}
fclose(shit);
- shit = fopen("debug/dump7.bin", "wb");
+ shit = fopen("debug/picto7.bin", "wb");
for (u32 i = 0x02000000; i < 0x04000000; i+=4)
{
u32 val = DSi::ARM7Read32(i);
diff --git a/src/NDS.h b/src/NDS.h
index e0a5045..91bfd1c 100644
--- a/src/NDS.h
+++ b/src/NDS.h
@@ -47,6 +47,8 @@ enum
Event_DSi_SDIOTransfer,
Event_DSi_NWifi,
+ Event_DSi_RAMSizeChange,
+
Event_MAX
};
diff --git a/src/SPI.cpp b/src/SPI.cpp
index eff0a05..2ba5e66 100644
--- a/src/SPI.cpp
+++ b/src/SPI.cpp
@@ -179,24 +179,25 @@ void Reset()
//Firmware[userdata+0x64] &= 0xBF;
*(u16*)&Firmware[userdata+0x72] = CRC16(&Firmware[userdata], 0x70, 0xFFFF);
+
+ if (Config::RandomizeMAC)
+ {
+ // replace MAC address with random address
+ Firmware[0x36] = 0x00;
+ Firmware[0x37] = 0x09;
+ Firmware[0x38] = 0xBF;
+ Firmware[0x39] = rand()&0xFF;
+ Firmware[0x3A] = rand()&0xFF;
+ Firmware[0x3B] = rand()&0xFF;
+
+ *(u16*)&Firmware[0x2A] = CRC16(&Firmware[0x2C], *(u16*)&Firmware[0x2C], 0x0000);
+ }
}
-#if 0
- // replace MAC address with random address
- // TODO: make optional?
- Firmware[0x36] = 0x00;
- Firmware[0x37] = 0x09;
- Firmware[0x38] = 0xBF;
- Firmware[0x39] = rand()&0xFF;
- Firmware[0x3A] = rand()&0xFF;
- Firmware[0x3B] = rand()&0xFF;
-#endif
printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
Firmware[0x36], Firmware[0x37], Firmware[0x38],
Firmware[0x39], Firmware[0x3A], Firmware[0x3B]);
- //*(u16*)&Firmware[0x2A] = CRC16(&Firmware[0x2C], *(u16*)&Firmware[0x2C], 0x0000);
-
// verify shit
printf("FW: WIFI CRC16 = %s\n", VerifyCRC16(0x0000, 0x2C, *(u16*)&Firmware[0x2C], 0x2A)?"GOOD":"BAD");
printf("FW: AP1 CRC16 = %s\n", VerifyCRC16(0x0000, 0x7FA00&FirmwareMask, 0xFE, 0x7FAFE&FirmwareMask)?"GOOD":"BAD");
@@ -241,6 +242,7 @@ void SetupDirectBoot()
u8 GetConsoleType() { return Firmware[0x1D]; }
u8 GetWifiVersion() { return Firmware[0x2F]; }
+u8 GetNWifiVersion() { return Firmware[0x1FD]; } // for DSi; will return 0xFF on a DS
u8 GetRFVersion() { return Firmware[0x40]; }
u8* GetWifiMAC() { return &Firmware[0x36]; }
diff --git a/src/SPI.h b/src/SPI.h
index 21734c4..0e0eb5a 100644
--- a/src/SPI.h
+++ b/src/SPI.h
@@ -28,6 +28,7 @@ void SetupDirectBoot();
u8 GetConsoleType();
u8 GetWifiVersion();
+u8 GetNWifiVersion();
u8 GetRFVersion();
u8* GetWifiMAC();
diff --git a/src/SPU.cpp b/src/SPU.cpp
index cd5c5b8..5b74bda 100644
--- a/src/SPU.cpp
+++ b/src/SPU.cpp
@@ -420,6 +420,8 @@ void Channel::Run(s32* buf, u32 samples)
{
if (!(Cnt & (1<<31))) return;
+ if ((type < 3) && ((Length+LoopPos) < 16)) return;
+
if (KeyOn)
{
Start();
diff --git a/src/Wifi.cpp b/src/Wifi.cpp
index 8188151..8a06041 100644
--- a/src/Wifi.cpp
+++ b/src/Wifi.cpp
@@ -816,6 +816,9 @@ bool CheckRX(bool block)
if (!(IOPORT(W_RXCnt) & 0x8000))
return false;
+ if (IOPORT(W_RXBufBegin) == IOPORT(W_RXBufEnd))
+ return false;
+
u16 framelen;
u16 framectl;
u8 txrate;
@@ -1049,7 +1052,7 @@ void USTimer(u32 param)
if (!(RXTime & RXHalfwordTimeMask))
{
u16 addr = IOPORT(W_RXTXAddr) << 1;
- *(u16*)&RAM[addr] = *(u16*)&RXBuffer[RXBufferPtr];
+ if (addr < 0x1FFF) *(u16*)&RAM[addr] = *(u16*)&RXBuffer[RXBufferPtr];
IncrementRXAddr(addr);
RXBufferPtr += 2;
@@ -1146,7 +1149,7 @@ void RFTransfer_Type3()
// TODO: wifi waitstates
u16 Read(u32 addr)
-{
+{//printf("WIFI READ %08X\n", addr);
if (addr >= 0x04810000)
return 0;
@@ -1236,7 +1239,7 @@ u16 Read(u32 addr)
}
void Write(u32 addr, u16 val)
-{
+{//printf("WIFI WRITE %08X %04X\n", addr, val);
if (addr >= 0x04810000)
return;
diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp
index 05a0c2d..b9d3235 100644
--- a/src/frontend/qt_sdl/Platform.cpp
+++ b/src/frontend/qt_sdl/Platform.cpp
@@ -77,7 +77,7 @@ u8 PacketBuffer[2048];
void Init(int argc, char** argv)
{
-#if defined(__WIN32__) || defined(UNIX_PORTABLE)
+#if defined(__WIN32__) || defined(PORTABLE)
if (argc > 0 && strlen(argv[0]) > 0)
{
int len = strlen(argv[0]);
@@ -167,7 +167,7 @@ FILE* OpenLocalFile(const char* path, const char* mode)
else
{
#ifdef PORTABLE
- fullpath = path;
+ fullpath = QString(EmuDirectory) + QDir::separator() + path;
#else
// Check user configuration directory
QDir config(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation));
diff --git a/src/frontend/qt_sdl/PlatformConfig.cpp b/src/frontend/qt_sdl/PlatformConfig.cpp
index 76c5f4b..4468d0e 100644
--- a/src/frontend/qt_sdl/PlatformConfig.cpp
+++ b/src/frontend/qt_sdl/PlatformConfig.cpp
@@ -51,7 +51,7 @@ int _3DRenderer;
int Threaded3D;
int GL_ScaleFactor;
-int GL_Antialias;
+int GL_BetterPolygons;
int LimitFPS;
int AudioSync;
@@ -135,15 +135,15 @@ ConfigEntry PlatformConfigFile[] =
{"IntegerScaling", 0, &IntegerScaling, 0, NULL, 0},
{"ScreenFilter", 0, &ScreenFilter, 1, NULL, 0},
- {"ScreenUseGL", 0, &ScreenUseGL, 1, NULL, 0},
+ {"ScreenUseGL", 0, &ScreenUseGL, 0, NULL, 0},
{"ScreenVSync", 0, &ScreenVSync, 0, NULL, 0},
{"ScreenVSyncInterval", 0, &ScreenVSyncInterval, 1, NULL, 0},
- {"3DRenderer", 0, &_3DRenderer, 1, NULL, 0},
+ {"3DRenderer", 0, &_3DRenderer, 0, NULL, 0},
{"Threaded3D", 0, &Threaded3D, 1, NULL, 0},
{"GL_ScaleFactor", 0, &GL_ScaleFactor, 1, NULL, 0},
- {"GL_Antialias", 0, &GL_Antialias, 0, NULL, 0},
+ {"GL_BetterPolygons", 0, &GL_BetterPolygons, 0, NULL, 0},
{"LimitFPS", 0, &LimitFPS, 0, NULL, 0},
{"AudioSync", 0, &AudioSync, 1, NULL, 0},
diff --git a/src/frontend/qt_sdl/PlatformConfig.h b/src/frontend/qt_sdl/PlatformConfig.h
index bc9bba4..9deee7f 100644
--- a/src/frontend/qt_sdl/PlatformConfig.h
+++ b/src/frontend/qt_sdl/PlatformConfig.h
@@ -64,7 +64,7 @@ extern int _3DRenderer;
extern int Threaded3D;
extern int GL_ScaleFactor;
-extern int GL_Antialias;
+extern int GL_BetterPolygons;
extern int LimitFPS;
extern int AudioSync;
diff --git a/src/frontend/qt_sdl/VideoSettingsDialog.cpp b/src/frontend/qt_sdl/VideoSettingsDialog.cpp
index ba433c3..ac1ed7a 100644
--- a/src/frontend/qt_sdl/VideoSettingsDialog.cpp
+++ b/src/frontend/qt_sdl/VideoSettingsDialog.cpp
@@ -167,3 +167,10 @@ void VideoSettingsDialog::on_cbxGLResolution_currentIndexChanged(int idx)
emit updateVideoSettings(false);
}
+
+void VideoSettingsDialog::on_cbBetterPolygons_stateChanged(int state)
+{
+ Config::GL_BetterPolygons = (state != 0);
+
+ emit updateVideoSettings(false);
+}
diff --git a/src/frontend/qt_sdl/VideoSettingsDialog.h b/src/frontend/qt_sdl/VideoSettingsDialog.h
index 2311d4d..f18793c 100644
--- a/src/frontend/qt_sdl/VideoSettingsDialog.h
+++ b/src/frontend/qt_sdl/VideoSettingsDialog.h
@@ -64,6 +64,7 @@ private slots:
void on_sbVSyncInterval_valueChanged(int val);
void on_cbxGLResolution_currentIndexChanged(int idx);
+ void on_cbBetterPolygons_stateChanged(int state);
void on_cbSoftwareThreaded_stateChanged(int state);
diff --git a/src/frontend/qt_sdl/VideoSettingsDialog.ui b/src/frontend/qt_sdl/VideoSettingsDialog.ui
index 6cdd5d8..6985304 100644
--- a/src/frontend/qt_sdl/VideoSettingsDialog.ui
+++ b/src/frontend/qt_sdl/VideoSettingsDialog.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>482</width>
- <height>237</height>
+ <height>244</height>
</rect>
</property>
<property name="sizePolicy">
@@ -43,6 +43,16 @@
</property>
</widget>
</item>
+ <item row="2" column="0">
+ <widget class="QCheckBox" name="cbBetterPolygons">
+ <property name="whatsThis">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enabling this may help reduce distortion on quads and more complex polygons, but may also reduce performance.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Improved polygon splitting</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
diff --git a/src/frontend/qt_sdl/WifiSettingsDialog.cpp b/src/frontend/qt_sdl/WifiSettingsDialog.cpp
index 457a78d..67297ad 100644
--- a/src/frontend/qt_sdl/WifiSettingsDialog.cpp
+++ b/src/frontend/qt_sdl/WifiSettingsDialog.cpp
@@ -17,7 +17,7 @@
*/
#include <stdio.h>
-#include <QFileDialog>
+#include <QMessageBox>
#include "types.h"
#include "Platform.h"
@@ -41,6 +41,10 @@
WifiSettingsDialog* WifiSettingsDialog::currentDlg = nullptr;
+bool WifiSettingsDialog::needsReset = false;
+
+extern bool RunningSomething;
+
WifiSettingsDialog::WifiSettingsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::WifiSettingsDialog)
{
@@ -53,6 +57,7 @@ WifiSettingsDialog::WifiSettingsDialog(QWidget* parent) : QDialog(parent), ui(ne
ui->cbDirectMode->setText("Direct mode (requires " PCAP_NAME " and ethernet connection)");
ui->cbBindAnyAddr->setChecked(Config::SocketBindAnyAddr != 0);
+ ui->cbRandomizeMAC->setChecked(Config::RandomizeMAC != 0);
int sel = 0;
for (int i = 0; i < LAN_PCap::NumAdapters; i++)
@@ -77,33 +82,49 @@ WifiSettingsDialog::~WifiSettingsDialog()
delete ui;
}
-void WifiSettingsDialog::on_WifiSettingsDialog_accepted()
+void WifiSettingsDialog::done(int r)
{
- Config::SocketBindAnyAddr = ui->cbBindAnyAddr->isChecked() ? 1:0;
- Config::DirectLAN = ui->cbDirectMode->isChecked() ? 1:0;
+ needsReset = false;
- int sel = ui->cbxDirectAdapter->currentIndex();
- if (sel < 0 || sel >= LAN_PCap::NumAdapters) sel = 0;
- if (LAN_PCap::NumAdapters < 1)
- {
- Config::LANDevice[0] = '\0';
- }
- else
+ if (r == QDialog::Accepted)
{
- strncpy(Config::LANDevice, LAN_PCap::Adapters[sel].DeviceName, 127);
- Config::LANDevice[127] = '\0';
+ int randommac = ui->cbRandomizeMAC->isChecked() ? 1:0;
+
+ if (randommac != Config::RandomizeMAC)
+ {
+ if (RunningSomething
+ && QMessageBox::warning(this, "Reset necessary to apply changes",
+ "The emulation will be reset for the changes to take place.",
+ QMessageBox::Ok, QMessageBox::Cancel) != QMessageBox::Ok)
+ return;
+ }
+
+ Config::SocketBindAnyAddr = ui->cbBindAnyAddr->isChecked() ? 1:0;
+ Config::RandomizeMAC = randommac;
+ Config::DirectLAN = ui->cbDirectMode->isChecked() ? 1:0;
+
+ int sel = ui->cbxDirectAdapter->currentIndex();
+ if (sel < 0 || sel >= LAN_PCap::NumAdapters) sel = 0;
+ if (LAN_PCap::NumAdapters < 1)
+ {
+ Config::LANDevice[0] = '\0';
+ }
+ else
+ {
+ strncpy(Config::LANDevice, LAN_PCap::Adapters[sel].DeviceName, 127);
+ Config::LANDevice[127] = '\0';
+ }
+
+ Config::Save();
+
+ needsReset = true;
}
- Config::Save();
+ QDialog::done(r);
closeDlg();
}
-void WifiSettingsDialog::on_WifiSettingsDialog_rejected()
-{
- closeDlg();
-}
-
void WifiSettingsDialog::on_cbDirectMode_stateChanged(int state)
{
updateAdapterControls();
diff --git a/src/frontend/qt_sdl/WifiSettingsDialog.h b/src/frontend/qt_sdl/WifiSettingsDialog.h
index f8aad1b..6c1f863 100644
--- a/src/frontend/qt_sdl/WifiSettingsDialog.h
+++ b/src/frontend/qt_sdl/WifiSettingsDialog.h
@@ -42,7 +42,7 @@ public:
}
currentDlg = new WifiSettingsDialog(parent);
- currentDlg->show();
+ currentDlg->open();
return currentDlg;
}
static void closeDlg()
@@ -50,9 +50,10 @@ public:
currentDlg = nullptr;
}
+ static bool needsReset;
+
private slots:
- void on_WifiSettingsDialog_accepted();
- void on_WifiSettingsDialog_rejected();
+ void done(int r);
void on_cbDirectMode_stateChanged(int state);
void on_cbxDirectAdapter_currentIndexChanged(int sel);
diff --git a/src/frontend/qt_sdl/WifiSettingsDialog.ui b/src/frontend/qt_sdl/WifiSettingsDialog.ui
index bfee1fd..6668d88 100644
--- a/src/frontend/qt_sdl/WifiSettingsDialog.ui
+++ b/src/frontend/qt_sdl/WifiSettingsDialog.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>479</width>
- <height>217</height>
+ <height>240</height>
</rect>
</property>
<property name="sizePolicy">
@@ -39,6 +39,16 @@
</property>
</widget>
</item>
+ <item row="1" column="0">
+ <widget class="QCheckBox" name="cbRandomizeMAC">
+ <property name="whatsThis">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Randomizes the console's MAC address upon reset. Required for local multiplayer if each melonDS instance uses the same firmware file.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Randomize MAC address</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp
index f91f879..f8cdd24 100644
--- a/src/frontend/qt_sdl/main.cpp
+++ b/src/frontend/qt_sdl/main.cpp
@@ -405,8 +405,11 @@ void EmuThread::run()
videoRenderer = hasOGL ? Config::_3DRenderer : 0;
videoSettingsDirty = false;
+
videoSettings.Soft_Threaded = Config::Threaded3D != 0;
videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor;
+ videoSettings.GL_BetterPolygons = Config::GL_BetterPolygons;
+
GPU::SetRenderSettings(videoRenderer, videoSettings);
}
@@ -1333,7 +1336,7 @@ void MainWindow::dragEnterEvent(QDragEnterEvent* event)
QString filename = urls.at(0).toLocalFile();
QString ext = filename.right(3);
- if (ext == "nds" || ext == "srl" || (ext == "gba" && RunningSomething))
+ if (ext == "nds" || ext == "srl" || ext == "dsi" || (ext == "gba" && RunningSomething))
event->acceptProposedAction();
}
@@ -1747,14 +1750,14 @@ void MainWindow::onAudioSettingsFinished(int res)
void MainWindow::onOpenWifiSettings()
{
+ emuThread->emuPause();
+
WifiSettingsDialog* dlg = WifiSettingsDialog::openDlg(this);
connect(dlg, &WifiSettingsDialog::finished, this, &MainWindow::onWifiSettingsFinished);
}
void MainWindow::onWifiSettingsFinished(int res)
{
- emuThread->emuPause();
-
if (Wifi::MPInited)
{
Platform::MP_DeInit();
@@ -1764,6 +1767,9 @@ void MainWindow::onWifiSettingsFinished(int res)
Platform::LAN_DeInit();
Platform::LAN_Init();
+ if (WifiSettingsDialog::needsReset)
+ onReset();
+
emuThread->emuUnpause();
}
@@ -1874,14 +1880,27 @@ void MainWindow::onTitleUpdate(QString title)
void MainWindow::onEmuStart()
{
- for (int i = 1; i < 9; i++)
+ // TODO: make savestates work in DSi mode!!
+ if (Config::ConsoleType == 1)
{
- actSaveState[i]->setEnabled(true);
- actLoadState[i]->setEnabled(Frontend::SavestateExists(i));
+ for (int i = 0; i < 9; i++)
+ {
+ actSaveState[i]->setEnabled(false);
+ actLoadState[i]->setEnabled(false);
+ }
+ actUndoStateLoad->setEnabled(false);
+ }
+ else
+ {
+ for (int i = 1; i < 9; i++)
+ {
+ actSaveState[i]->setEnabled(true);
+ actLoadState[i]->setEnabled(Frontend::SavestateExists(i));
+ }
+ actSaveState[0]->setEnabled(true);
+ actLoadState[0]->setEnabled(true);
+ actUndoStateLoad->setEnabled(false);
}
- actSaveState[0]->setEnabled(true);
- actLoadState[0]->setEnabled(true);
- actUndoStateLoad->setEnabled(false);
actPause->setEnabled(true);
actPause->setChecked(false);
@@ -2066,7 +2085,7 @@ int main(int argc, char** argv)
char* file = argv[1];
char* ext = &file[strlen(file)-3];
- if (!strcasecmp(ext, "nds") || !strcasecmp(ext, "srl"))
+ if (!strcasecmp(ext, "nds") || !strcasecmp(ext, "srl") || !strcasecmp(ext, "dsi"))
{
int res = Frontend::LoadROM(file, Frontend::ROMSlot_NDS);