aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArisotura <thetotalworm@gmail.com>2020-05-30 03:04:14 +0200
committerArisotura <thetotalworm@gmail.com>2020-05-30 03:04:14 +0200
commitb44570eba1aab5903ff99aac044dc3e777c264d3 (patch)
tree11a05b343c764c71f564a3774212a7e58818819d
parent61799c35bdf26a5754ca760ac92d4f07d6a9396b (diff)
parent9381b531cd4544cc68998f604211bcbffb90cd3c (diff)
merge moar
-rw-r--r--.gitignore1
-rw-r--r--src/ARM.h3
-rw-r--r--src/CP15.cpp307
-rw-r--r--src/GPU2D.cpp99
-rw-r--r--src/GPU2D.h5
-rw-r--r--src/GPU3D_OpenGL.cpp3
-rw-r--r--src/libui_sdl/main.cpp39
7 files changed, 294 insertions, 163 deletions
diff --git a/.gitignore b/.gitignore
index bd1d485..dd81614 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+build
bin
obj
*.depend
diff --git a/src/ARM.h b/src/ARM.h
index 6b6e330..a8a7bb3 100644
--- a/src/ARM.h
+++ b/src/ARM.h
@@ -212,7 +212,8 @@ public:
void UpdateDTCMSetting();
void UpdateITCMSetting();
- void UpdatePURegions();
+ void UpdatePURegion(u32 n);
+ void UpdatePURegions(bool update_all);
u32 RandomLineIndex();
diff --git a/src/CP15.cpp b/src/CP15.cpp
index 4654a2a..d412db6 100644
--- a/src/CP15.cpp
+++ b/src/CP15.cpp
@@ -60,7 +60,7 @@ void ARMv5::CP15Reset()
PU_DataRW = 0;
memset(PU_Region, 0, 8*sizeof(u32));
- UpdatePURegions();
+ UpdatePURegions(true);
CurICacheLine = NULL;
}
@@ -90,7 +90,7 @@ void ARMv5::CP15DoSavestate(Savestate* file)
{
UpdateDTCMSetting();
UpdateITCMSetting();
- UpdatePURegions();
+ UpdatePURegions(true);
}
}
@@ -126,27 +126,12 @@ void ARMv5::UpdateITCMSetting()
}
-void ARMv5::UpdatePURegions()
+// covers updates to a specific PU region's cache/etc settings
+// (not to the region range/enabled status)
+void ARMv5::UpdatePURegion(u32 n)
{
- if (!(CP15Control & (1<<0)))
- {
- // PU disabled
-
- u8 mask = 0x07;
- if (CP15Control & (1<<2)) mask |= 0x30;
- if (CP15Control & (1<<12)) mask |= 0x40;
-
- memset(PU_UserMap, mask, 0x100000);
- memset(PU_PrivMap, mask, 0x100000);
-
- return;
- }
-
- memset(PU_UserMap, 0, 0x100000);
- memset(PU_PrivMap, 0, 0x100000);
-
- u32 coderw = PU_CodeRW;
- u32 datarw = PU_DataRW;
+ u32 coderw = (PU_CodeRW >> (4*n)) & 0xF;
+ u32 datarw = (PU_DataRW >> (4*n)) & 0xF;
u32 codecache, datacache, datawrite;
@@ -157,14 +142,14 @@ void ARMv5::UpdatePURegions()
// 1/1: goes to cache
if (CP15Control & (1<<12))
- codecache = PU_CodeCacheable;
+ codecache = (PU_CodeCacheable >> n) & 0x1;
else
codecache = 0;
if (CP15Control & (1<<2))
{
- datacache = PU_DataCacheable;
- datawrite = PU_DataCacheWrite;
+ datacache = (PU_DataCacheable >> n) & 0x1;
+ datawrite = (PU_DataCacheWrite >> n) & 0x1;
}
else
{
@@ -172,88 +157,102 @@ void ARMv5::UpdatePURegions()
datawrite = 0;
}
- for (int n = 0; n < 8; n++)
+ u32 rgn = PU_Region[n];
+ if (!(rgn & (1<<0)))
{
- u32 rgn = PU_Region[n];
- if (!(rgn & (1<<0)))
- {
- coderw >>= 4;
- datarw >>= 4;
- codecache >>= 1;
- datacache >>= 1;
- datawrite >>= 1;
- continue;
- }
+ return;
+ }
- u32 start = rgn >> 12;
- u32 sz = 2 << ((rgn >> 1) & 0x1F);
- u32 end = start + (sz >> 12);
- // TODO: check alignment of start
+ u32 start = rgn >> 12;
+ u32 sz = 2 << ((rgn >> 1) & 0x1F);
+ u32 end = start + (sz >> 12);
+ // TODO: check alignment of start
- u8 usermask = 0;
- u8 privmask = 0;
+ u8 usermask = 0;
+ u8 privmask = 0;
- switch (datarw & 0xF)
- {
- case 0: break;
- case 1: privmask |= 0x03; break;
- case 2: privmask |= 0x03; usermask |= 0x01; break;
- case 3: privmask |= 0x03; usermask |= 0x03; break;
- case 5: privmask |= 0x01; break;
- case 6: privmask |= 0x01; usermask |= 0x01; break;
- default: printf("!! BAD DATARW VALUE %d\n", datarw&0xF);
- }
+ switch (datarw)
+ {
+ case 0: break;
+ case 1: privmask |= 0x03; break;
+ case 2: privmask |= 0x03; usermask |= 0x01; break;
+ case 3: privmask |= 0x03; usermask |= 0x03; break;
+ case 5: privmask |= 0x01; break;
+ case 6: privmask |= 0x01; usermask |= 0x01; break;
+ default: printf("!! BAD DATARW VALUE %d\n", datarw&0xF);
+ }
- switch (coderw & 0xF)
+ switch (coderw)
+ {
+ case 0: break;
+ case 1: privmask |= 0x04; break;
+ case 2: privmask |= 0x04; usermask |= 0x04; break;
+ case 3: privmask |= 0x04; usermask |= 0x04; break;
+ case 5: privmask |= 0x04; break;
+ case 6: privmask |= 0x04; usermask |= 0x04; break;
+ default: printf("!! BAD CODERW VALUE %d\n", datarw&0xF);
+ }
+
+ if (datacache & 0x1)
+ {
+ privmask |= 0x10;
+ usermask |= 0x10;
+
+ if (datawrite & 0x1)
{
- case 0: break;
- case 1: privmask |= 0x04; break;
- case 2: privmask |= 0x04; usermask |= 0x04; break;
- case 3: privmask |= 0x04; usermask |= 0x04; break;
- case 5: privmask |= 0x04; break;
- case 6: privmask |= 0x04; usermask |= 0x04; break;
- default: printf("!! BAD CODERW VALUE %d\n", datarw&0xF);
+ privmask |= 0x20;
+ usermask |= 0x20;
}
+ }
- if (datacache & 0x1)
- {
- privmask |= 0x10;
- usermask |= 0x10;
+ if (codecache & 0x1)
+ {
+ privmask |= 0x40;
+ usermask |= 0x40;
+ }
- if (datawrite & 0x1)
- {
- privmask |= 0x20;
- usermask |= 0x20;
- }
- }
+ //printf("PU region %d: %08X-%08X, user=%02X priv=%02X\n", n, start<<12, end<<12, usermask, privmask);
- if (codecache & 0x1)
- {
- privmask |= 0x40;
- usermask |= 0x40;
- }
+ for (u32 i = start; i < end; i++)
+ {
+ PU_UserMap[i] = usermask;
+ PU_PrivMap[i] = privmask;
+ }
- printf("PU region %d: %08X-%08X, user=%02X priv=%02X\n", n, start<<12, end<<12, usermask, privmask);
+ UpdateRegionTimings(start<<12, end<<12);
+}
- for (u32 i = start; i < end; i++)
- {
- PU_UserMap[i] = usermask;
- PU_PrivMap[i] = privmask;
- }
+void ARMv5::UpdatePURegions(bool update_all)
+{
+ if (!(CP15Control & (1<<0)))
+ {
+ // PU disabled
- coderw >>= 4;
- datarw >>= 4;
- codecache >>= 1;
- datacache >>= 1;
- datawrite >>= 1;
+ u8 mask = 0x07;
+ if (CP15Control & (1<<2)) mask |= 0x30;
+ if (CP15Control & (1<<12)) mask |= 0x40;
+
+ memset(PU_UserMap, mask, 0x100000);
+ memset(PU_PrivMap, mask, 0x100000);
+
+ UpdateRegionTimings(0x00000000, 0xFFFFFFFF);
+ return;
+ }
+
+ if (update_all)
+ {
+ memset(PU_UserMap, 0, 0x100000);
+ memset(PU_PrivMap, 0, 0x100000);
+ }
- // TODO: this will not be enough if they change their PU regions after the intial setup
- //UpdateRegionTimings(start<<12, end<<12);
+ for (int n = 0; n < 8; n++)
+ {
+ UpdatePURegion(n);
}
// TODO: this is way unoptimized
// should be okay unless the game keeps changing shit, tho
- UpdateRegionTimings(0x00000000, 0xFFFFFFFF);
+ if (update_all) UpdateRegionTimings(0x00000000, 0xFFFFFFFF);
}
void ARMv5::UpdateRegionTimings(u32 addrstart, u32 addrend)
@@ -303,7 +302,6 @@ u32 ARMv5::RandomLineIndex()
return (RNGSeed >> 17) & 0x3;
}
-int zog=1;
void ARMv5::ICacheLookup(u32 addr)
{
u32 tag = addr & 0xFFFFF800;
@@ -312,25 +310,25 @@ void ARMv5::ICacheLookup(u32 addr)
id <<= 2;
if (ICacheTags[id+0] == tag)
{
- CodeCycles = 1;zog=1;
+ CodeCycles = 1;
CurICacheLine = &ICache[(id+0) << 5];
return;
}
if (ICacheTags[id+1] == tag)
{
- CodeCycles = 1;zog=2;
+ CodeCycles = 1;
CurICacheLine = &ICache[(id+1) << 5];
return;
}
if (ICacheTags[id+2] == tag)
{
- CodeCycles = 1;zog=3;
+ CodeCycles = 1;
CurICacheLine = &ICache[(id+2) << 5];
return;
}
if (ICacheTags[id+3] == tag)
{
- CodeCycles = 1;zog=4;
+ CodeCycles = 1;
CurICacheLine = &ICache[(id+3) << 5];
return;
}
@@ -418,10 +416,13 @@ void ARMv5::CP15Write(u32 id, u32 val)
val &= 0x000FF085;
CP15Control &= ~0x000FF085;
CP15Control |= val;
- printf("CP15Control = %08X (%08X->%08X)\n", CP15Control, old, val);
+ //printf("CP15Control = %08X (%08X->%08X)\n", CP15Control, old, val);
UpdateDTCMSetting();
UpdateITCMSetting();
- if ((old & 0x1005) != (val & 0x1005)) UpdatePURegions();
+ if ((old & 0x1005) != (val & 0x1005))
+ {
+ UpdatePURegions((old & 0x1) != (val & 0x1));
+ }
if (val & (1<<7)) printf("!!!! ARM9 BIG ENDIAN MODE. VERY BAD. SHIT GONNA ASPLODE NOW\n");
if (val & (1<<13)) ExceptionBase = 0xFFFF0000;
else ExceptionBase = 0x00000000;
@@ -430,63 +431,100 @@ void ARMv5::CP15Write(u32 id, u32 val)
case 0x200: // data cacheable
- PU_DataCacheable = val;
- printf("PU: DataCacheable=%08X\n", val);
- UpdatePURegions();
+ {
+ u32 diff = PU_DataCacheable ^ val;
+ PU_DataCacheable = val;
+ for (u32 i = 0; i < 8; i++)
+ {
+ if (diff & (1<<i)) UpdatePURegion(i);
+ }
+ }
return;
case 0x201: // code cacheable
- PU_CodeCacheable = val;
- printf("PU: CodeCacheable=%08X\n", val);
- UpdatePURegions();
+ {
+ u32 diff = PU_CodeCacheable ^ val;
+ PU_CodeCacheable = val;
+ for (u32 i = 0; i < 8; i++)
+ {
+ if (diff & (1<<i)) UpdatePURegion(i);
+ }
+ }
return;
case 0x300: // data cache write-buffer
- PU_DataCacheWrite = val;
- printf("PU: DataCacheWrite=%08X\n", val);
- UpdatePURegions();
+ {
+ u32 diff = PU_DataCacheWrite ^ val;
+ PU_DataCacheWrite = val;
+ for (u32 i = 0; i < 8; i++)
+ {
+ if (diff & (1<<i)) UpdatePURegion(i);
+ }
+ }
return;
case 0x500: // legacy data permissions
- PU_DataRW = 0;
- PU_DataRW |= (val & 0x0003);
- PU_DataRW |= ((val & 0x000C) << 2);
- PU_DataRW |= ((val & 0x0030) << 4);
- PU_DataRW |= ((val & 0x00C0) << 6);
- PU_DataRW |= ((val & 0x0300) << 8);
- PU_DataRW |= ((val & 0x0C00) << 10);
- PU_DataRW |= ((val & 0x3000) << 12);
- PU_DataRW |= ((val & 0xC000) << 14);
- printf("PU: DataRW=%08X (legacy %08X)\n", PU_DataRW, val);
- UpdatePURegions();
+ {
+ u32 old = PU_DataRW;
+ PU_DataRW = 0;
+ PU_DataRW |= (val & 0x0003);
+ PU_DataRW |= ((val & 0x000C) << 2);
+ PU_DataRW |= ((val & 0x0030) << 4);
+ PU_DataRW |= ((val & 0x00C0) << 6);
+ PU_DataRW |= ((val & 0x0300) << 8);
+ PU_DataRW |= ((val & 0x0C00) << 10);
+ PU_DataRW |= ((val & 0x3000) << 12);
+ PU_DataRW |= ((val & 0xC000) << 14);
+ u32 diff = old ^ PU_DataRW;
+ for (u32 i = 0; i < 8; i++)
+ {
+ if (diff & (0xF<<(i*4))) UpdatePURegion(i);
+ }
+ }
return;
case 0x501: // legacy code permissions
- PU_CodeRW = 0;
- PU_CodeRW |= (val & 0x0003);
- PU_CodeRW |= ((val & 0x000C) << 2);
- PU_CodeRW |= ((val & 0x0030) << 4);
- PU_CodeRW |= ((val & 0x00C0) << 6);
- PU_CodeRW |= ((val & 0x0300) << 8);
- PU_CodeRW |= ((val & 0x0C00) << 10);
- PU_CodeRW |= ((val & 0x3000) << 12);
- PU_CodeRW |= ((val & 0xC000) << 14);
- printf("PU: CodeRW=%08X (legacy %08X)\n", PU_CodeRW, val);
- UpdatePURegions();
+ {
+ u32 old = PU_CodeRW;
+ PU_CodeRW = 0;
+ PU_CodeRW |= (val & 0x0003);
+ PU_CodeRW |= ((val & 0x000C) << 2);
+ PU_CodeRW |= ((val & 0x0030) << 4);
+ PU_CodeRW |= ((val & 0x00C0) << 6);
+ PU_CodeRW |= ((val & 0x0300) << 8);
+ PU_CodeRW |= ((val & 0x0C00) << 10);
+ PU_CodeRW |= ((val & 0x3000) << 12);
+ PU_CodeRW |= ((val & 0xC000) << 14);
+ u32 diff = old ^ PU_CodeRW;
+ for (u32 i = 0; i < 8; i++)
+ {
+ if (diff & (0xF<<(i*4))) UpdatePURegion(i);
+ }
+ }
return;
case 0x502: // data permissions
- PU_DataRW = val;
- printf("PU: DataRW=%08X\n", PU_DataRW);
- UpdatePURegions();
+ {
+ u32 diff = PU_DataRW ^ val;
+ PU_DataRW = val;
+ for (u32 i = 0; i < 8; i++)
+ {
+ if (diff & (0xF<<(i*4))) UpdatePURegion(i);
+ }
+ }
return;
case 0x503: // code permissions
- PU_CodeRW = val;
- printf("PU: CodeRW=%08X\n", PU_CodeRW);
- UpdatePURegions();
+ {
+ u32 diff = PU_CodeRW ^ val;
+ PU_CodeRW = val;
+ for (u32 i = 0; i < 8; i++)
+ {
+ if (diff & (0xF<<(i*4))) UpdatePURegion(i);
+ }
+ }
return;
@@ -511,7 +549,8 @@ void ARMv5::CP15Write(u32 id, u32 val)
printf("%s, ", val&1 ? "enabled":"disabled");
printf("%08X-", val&0xFFFFF000);
printf("%08X\n", (val&0xFFFFF000)+(2<<((val&0x3E)>>1)));
- UpdatePURegions();
+ // TODO: smarter region update for this?
+ UpdatePURegions(true);
return;
diff --git a/src/GPU2D.cpp b/src/GPU2D.cpp
index b510767..30a6d45 100644
--- a/src/GPU2D.cpp
+++ b/src/GPU2D.cpp
@@ -943,8 +943,8 @@ void GPU2D::VBlankEnd()
BGMosaicYMax = BGMosaicSize[1];
//OBJMosaicY = 0;
//OBJMosaicYMax = OBJMosaicSize[1];
- OBJMosaicY = 0;
- OBJMosaicYCount = 0;
+ //OBJMosaicY = 0;
+ //OBJMosaicYCount = 0;
if (Accelerated)
{
@@ -2238,6 +2238,13 @@ void GPU2D::DrawBG_Large(u32 line) // BG is always BG2
BGYRefInternal[0] += rotD;
}
+// OBJ line buffer:
+// * bit0-15: color (bit15=1: direct color, bit15=0: palette index, bit12=0 to indicate extpal)
+// * bit16-17: BG-relative priority
+// * bit18: non-transparent sprite pixel exists here
+// * bit19: X mosaic should be applied here
+// * bit24-31: compositor flags
+
void GPU2D::ApplySpriteMosaicX()
{
// apply X mosaic if needed
@@ -2255,7 +2262,7 @@ void GPU2D::ApplySpriteMosaicX()
continue;
}
- if ((!(OBJLine[i-1] & 0x100000)) || (CurOBJXMosaicTable[i] == 0))
+ if ((OBJIndex[i] != OBJIndex[i-1]) || (CurOBJXMosaicTable[i] == 0))
lastcolor = OBJLine[i];
else
OBJLine[i] = lastcolor;
@@ -2322,11 +2329,25 @@ void GPU2D::InterleaveSprites(u32 prio)
void GPU2D::DrawSprites(u32 line)
{
+ if (line == 0)
+ {
+ // reset those counters here
+ // TODO: find out when those are supposed to be reset
+ // it would make sense to reset them at the end of VBlank
+ // however, sprites are rendered one scanline in advance
+ // so they need to be reset a bit earlier
+
+ OBJMosaicY = 0;
+ OBJMosaicYCount = 0;
+ }
+
NumSprites = 0;
memset(OBJLine, 0, 256*4);
memset(OBJWindow, 0, 256);
if (!(DispCnt & 0x1000)) return;
+ memset(OBJIndex, 0xFF, 256);
+
u16* oam = (u16*)&GPU::OAM[Num ? 0x400 : 0];
const s32 spritewidth[16] =
@@ -2355,6 +2376,15 @@ void GPU2D::DrawSprites(u32 line)
bool iswin = (((attrib[0] >> 10) & 0x3) == 2);
+ u32 sprline;
+ if ((attrib[0] & 0x1000) && !iswin)
+ {
+ // apply Y mosaic
+ sprline = OBJMosaicY;
+ }
+ else
+ sprline = line;
+
if (attrib[0] & 0x0100)
{
u32 sizeparam = (attrib[0] >> 14) | ((attrib[1] & 0xC000) >> 12);
@@ -2370,7 +2400,7 @@ void GPU2D::DrawSprites(u32 line)
}
u32 ypos = attrib[0] & 0xFF;
- ypos = (line - ypos) & 0xFF;
+ ypos = (sprline - ypos) & 0xFF;
if (ypos >= (u32)boundheight)
continue;
@@ -2380,7 +2410,7 @@ void GPU2D::DrawSprites(u32 line)
u32 rotparamgroup = (attrib[1] >> 9) & 0x1F;
- DoDrawSprite(Rotscale, attrib, &oam[(rotparamgroup*16) + 3], boundwidth, boundheight, width, height, xpos, ypos);
+ DoDrawSprite(Rotscale, sprnum, boundwidth, boundheight, width, height, xpos, ypos);
NumSprites++;
}
@@ -2394,7 +2424,7 @@ void GPU2D::DrawSprites(u32 line)
s32 height = spriteheight[sizeparam];
u32 ypos = attrib[0] & 0xFF;
- ypos = (line - ypos) & 0xFF;
+ ypos = (sprline - ypos) & 0xFF;
if (ypos >= (u32)height)
continue;
@@ -2402,11 +2432,7 @@ void GPU2D::DrawSprites(u32 line)
if (xpos <= -width)
continue;
- // yflip
- if (attrib[1] & 0x2000)
- ypos = height-1 - ypos;
-
- DoDrawSprite(Normal, attrib, width, xpos, ypos);
+ DoDrawSprite(Normal, sprnum, width, height, xpos, ypos);
NumSprites++;
}
@@ -2415,8 +2441,12 @@ void GPU2D::DrawSprites(u32 line)
}
template<bool window>
-void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32 boundheight, u32 width, u32 height, s32 xpos, s32 ypos)
+void GPU2D::DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 width, u32 height, s32 xpos, s32 ypos)
{
+ u16* oam = (u16*)&GPU::OAM[Num ? 0x400 : 0];
+ u16* attrib = &oam[num * 4];
+ u16* rotparams = &oam[(((attrib[1] >> 9) & 0x1F) * 16) + 3];
+
u32 pixelattr = ((attrib[2] & 0x0C00) << 6) | 0xC0000;
u32 tilenum = attrib[2] & 0x03FF;
u32 spritemode = window ? 0 : ((attrib[0] >> 10) & 0x3);
@@ -2429,9 +2459,6 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
if ((attrib[0] & 0x1000) && !window)
{
// apply Y mosaic
- ypos = OBJMosaicY - (attrib[0] & 0xFF);
- if (ypos < 0) ypos = 0;
-
pixelattr |= 0x100000;
}
@@ -2509,12 +2536,15 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
if (color & 0x8000)
{
if (window) OBJWindow[xpos] = 1;
- else OBJLine[xpos] = color | pixelattr;
+ else { OBJLine[xpos] = color | pixelattr; OBJIndex[xpos] = num; }
}
else if (!window)
{
if (OBJLine[xpos] == 0)
+ {
OBJLine[xpos] = pixelattr & 0x180000;
+ OBJIndex[xpos] = num;
+ }
}
}
@@ -2563,12 +2593,15 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
if (color)
{
if (window) OBJWindow[xpos] = 1;
- else OBJLine[xpos] = color | pixelattr;
+ else { OBJLine[xpos] = color | pixelattr; OBJIndex[xpos] = num; }
}
else if (!window)
{
if (OBJLine[xpos] == 0)
+ {
OBJLine[xpos] = pixelattr & 0x180000;
+ OBJIndex[xpos] = num;
+ }
}
}
@@ -2604,12 +2637,15 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
if (color)
{
if (window) OBJWindow[xpos] = 1;
- else OBJLine[xpos] = color | pixelattr;
+ else { OBJLine[xpos] = color | pixelattr; OBJIndex[xpos] = num; }
}
else if (!window)
{
if (OBJLine[xpos] == 0)
+ {
OBJLine[xpos] = pixelattr & 0x180000;
+ OBJIndex[xpos] = num;
+ }
}
}
@@ -2623,8 +2659,11 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32
}
template<bool window>
-void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
+void GPU2D::DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos)
{
+ u16* oam = (u16*)&GPU::OAM[Num ? 0x400 : 0];
+ u16* attrib = &oam[num * 4];
+
u32 pixelattr = ((attrib[2] & 0x0C00) << 6) | 0xC0000;
u32 tilenum = attrib[2] & 0x03FF;
u32 spritemode = window ? 0 : ((attrib[0] >> 10) & 0x3);
@@ -2634,12 +2673,13 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
if ((attrib[0] & 0x1000) && !window)
{
// apply Y mosaic
- ypos = OBJMosaicY - (attrib[0] & 0xFF);
- if (ypos < 0) ypos = 0;
-
pixelattr |= 0x100000;
}
+ // yflip
+ if (attrib[1] & 0x2000)
+ ypos = height-1 - ypos;
+
u32 xoff;
u32 xend = width;
if (xpos >= 0)
@@ -2719,12 +2759,15 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
if (color & 0x8000)
{
if (window) OBJWindow[xpos] = 1;
- else OBJLine[xpos] = color | pixelattr;
+ else { OBJLine[xpos] = color | pixelattr; OBJIndex[xpos] = num; }
}
else if (!window)
{
if (OBJLine[xpos] == 0)
+ {
OBJLine[xpos] = pixelattr & 0x180000;
+ OBJIndex[xpos] = num;
+ }
}
xoff++;
@@ -2786,12 +2829,15 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
if (color)
{
if (window) OBJWindow[xpos] = 1;
- else OBJLine[xpos] = color | pixelattr;
+ else { OBJLine[xpos] = color | pixelattr; OBJIndex[xpos] = num; }
}
else if (!window)
{
if (OBJLine[xpos] == 0)
+ {
OBJLine[xpos] = pixelattr & 0x180000;
+ OBJIndex[xpos] = num;
+ }
}
xoff++;
@@ -2847,12 +2893,15 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos)
if (color)
{
if (window) OBJWindow[xpos] = 1;
- else OBJLine[xpos] = color | pixelattr;
+ else { OBJLine[xpos] = color | pixelattr; OBJIndex[xpos] = num; }
}
else if (!window)
{
if (OBJLine[xpos] == 0)
+ {
OBJLine[xpos] = pixelattr & 0x180000;
+ OBJIndex[xpos] = num;
+ }
}
xoff++;
diff --git a/src/GPU2D.h b/src/GPU2D.h
index 8c6ec27..6675ce7 100644
--- a/src/GPU2D.h
+++ b/src/GPU2D.h
@@ -78,6 +78,7 @@ private:
u8 WindowMask[256] __attribute__((aligned (8)));
u32 OBJLine[256] __attribute__((aligned (8)));
u8 OBJWindow[256] __attribute__((aligned (8)));
+ u8 OBJIndex[256] __attribute__((aligned (8)));
u32 NumSprites;
@@ -156,8 +157,8 @@ private:
void ApplySpriteMosaicX();
void InterleaveSprites(u32 prio);
- template<bool window> void DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32 boundheight, u32 width, u32 height, s32 xpos, s32 ypos);
- template<bool window> void DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos);
+ template<bool window> void DrawSprite_Rotscale(u32 num, u32 boundwidth, u32 boundheight, u32 width, u32 height, s32 xpos, s32 ypos);
+ template<bool window> void DrawSprite_Normal(u32 num, u32 width, u32 height, s32 xpos, s32 ypos);
void DoCapture(u32 line, u32 width);
diff --git a/src/GPU3D_OpenGL.cpp b/src/GPU3D_OpenGL.cpp
index d616e1c..6abb1ab 100644
--- a/src/GPU3D_OpenGL.cpp
+++ b/src/GPU3D_OpenGL.cpp
@@ -807,7 +807,6 @@ void RenderSceneChunk(int y, int h)
else
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ONE);
- UseRenderShader(flags | RenderFlag_Trans);
glLineWidth(1.0);
if (NumOpaqueFinalPolys > -1)
@@ -843,6 +842,8 @@ void RenderSceneChunk(int y, int h)
}
else if (rp->PolyData->Translucent)
{
+ UseRenderShader(flags | RenderFlag_Trans);
+
// zorp
glDepthFunc(GL_LESS);
diff --git a/src/libui_sdl/main.cpp b/src/libui_sdl/main.cpp
index 08d38b2..3d894f4 100644
--- a/src/libui_sdl/main.cpp
+++ b/src/libui_sdl/main.cpp
@@ -2662,6 +2662,45 @@ int main(int argc, char** argv)
SDL_Quit();
return 0;
}
+ if (!Platform::LocalFileExists("firmware.bin.bak"))
+ {
+ // verify the firmware
+ //
+ // there are dumps of an old hacked firmware floating around on the internet
+ // and those are problematic
+ // the hack predates WFC, and, due to this, any game that alters the WFC
+ // access point data will brick that firmware due to it having critical
+ // data in the same area. it has the same problem on hardware.
+ //
+ // but this should help stop users from reporting that issue over and over
+ // again, when the issue is not from melonDS but from their firmware dump.
+ //
+ // I don't know about all the firmware hacks in existence, but the one I
+ // looked at has 0x180 bytes from the header repeated at 0x3FC80, but
+ // bytes 0x0C-0x14 are different.
+
+ FILE* f = Platform::OpenLocalFile("firmware.bin", "rb");
+ u8 chk1[0x180], chk2[0x180];
+
+ fseek(f, 0, SEEK_SET);
+ fread(chk1, 1, 0x180, f);
+ fseek(f, -0x380, SEEK_END);
+ fread(chk2, 1, 0x180, f);
+
+ memset(&chk1[0x0C], 0, 8);
+ memset(&chk2[0x0C], 0, 8);
+
+ fclose(f);
+
+ if (!memcmp(chk1, chk2, 0x180))
+ {
+ uiMsgBoxError(NULL,
+ "Problematic firmware dump",
+ "You are using an old hacked firmware dump.\n"
+ "Firmware boot will stop working if you run any game that alters WFC settings.\n\n"
+ "Note that the issue is not from melonDS, it would also happen on an actual DS.");
+ }
+ }
{
FILE* f = Platform::OpenLocalFile("romlist.bin", "rb");
if (f)