diff options
-rw-r--r-- | src/GPU3D.cpp | 24 | ||||
-rw-r--r-- | src/GPU3D.h | 2 | ||||
-rw-r--r-- | src/GPU3D_Soft.cpp | 75 |
3 files changed, 89 insertions, 12 deletions
diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp index 9179d46..7ebe956 100644 --- a/src/GPU3D.cpp +++ b/src/GPU3D.cpp @@ -179,7 +179,7 @@ u16 RenderToonTable[32]; u16 RenderEdgeTable[8]; u32 RenderFogColor, RenderFogOffset; -u8 RenderFogDensityTable[32]; +u8 RenderFogDensityTable[34]; u32 RenderClearAttr1, RenderClearAttr2; @@ -1815,7 +1815,9 @@ void VBlank() RenderFogColor = FogColor; RenderFogOffset = FogOffset; - memcpy(RenderFogDensityTable, FogDensityTable, 32); + RenderFogDensityTable[0] = FogDensityTable[0]; + memcpy(&RenderFogDensityTable[1], FogDensityTable, 32); + RenderFogDensityTable[33] = FogDensityTable[31]; RenderClearAttr1 = ClearAttr1; RenderClearAttr2 = ClearAttr2; @@ -1988,7 +1990,7 @@ void Write8(u32 addr, u8 val) if (addr >= 0x04000360 && addr < 0x04000380) { - FogDensityTable[addr - 0x04000360] = val; + FogDensityTable[addr - 0x04000360] = val & 0x7F; return; } @@ -2031,7 +2033,7 @@ void Write16(u32 addr, u16 val) FogColor = (FogColor & 0xFFFF) | (val << 16); return; case 0x0400035C: - FogOffset = val; + FogOffset = val & 0x7FFF; return; } @@ -2044,8 +2046,8 @@ void Write16(u32 addr, u16 val) if (addr >= 0x04000360 && addr < 0x04000380) { addr -= 0x04000360; - FogDensityTable[addr] = val & 0xFF; - FogDensityTable[addr+1] = val >> 8; + FogDensityTable[addr] = val & 0x7F; + FogDensityTable[addr+1] = (val >> 8) & 0x7F; return; } @@ -2085,7 +2087,7 @@ void Write32(u32 addr, u32 val) FogColor = val; return; case 0x0400035C: - FogOffset = val; + FogOffset = val & 0x7FFF; return; case 0x04000600: @@ -2129,10 +2131,10 @@ void Write32(u32 addr, u32 val) if (addr >= 0x04000360 && addr < 0x04000380) { addr -= 0x04000360; - FogDensityTable[addr] = val & 0xFF; - FogDensityTable[addr+1] = (val >> 8) & 0xFF; - FogDensityTable[addr+2] = (val >> 16) & 0xFF; - FogDensityTable[addr+3] = val >> 24; + FogDensityTable[addr] = val & 0x7F; + FogDensityTable[addr+1] = (val >> 8) & 0x7F; + FogDensityTable[addr+2] = (val >> 16) & 0x7F; + FogDensityTable[addr+3] = (val >> 24) & 0x7F; return; } diff --git a/src/GPU3D.h b/src/GPU3D.h index 6c1b43c..1f98e8f 100644 --- a/src/GPU3D.h +++ b/src/GPU3D.h @@ -78,7 +78,7 @@ extern u16 RenderToonTable[32]; extern u16 RenderEdgeTable[8]; extern u32 RenderFogColor, RenderFogOffset; -extern u8 RenderFogDensityTable[32]; +extern u8 RenderFogDensityTable[34]; extern u32 RenderClearAttr1, RenderClearAttr2; diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp index fe97b5f..e7906a9 100644 --- a/src/GPU3D_Soft.cpp +++ b/src/GPU3D_Soft.cpp @@ -1027,6 +1027,9 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y) if ((dstattr & 0x7F000000) == (attr & 0x7F000000)) continue; + if (!(dstattr & (1<<15))) + attr &= ~(1<<15); + u32 dstcolor = ColorBuffer[pixeladdr]; u32 dstalpha = dstcolor >> 24; @@ -1106,6 +1109,78 @@ void RenderScanline(s32 y, int npolys) if (y >= polygon->YTop && (y < polygon->YBottom || (y == polygon->YTop && polygon->YBottom == polygon->YTop))) RenderPolygonScanline(rp, y); } + + if (RenderDispCnt & (1<<7)) + { + // fog + + // hardware testing shows that the fog step is 0x80000>>SHIFT + // basically, the depth values used in GBAtek need to be + // multiplied by 0x200 to match Z-buffer values + + bool fogcolor = !(RenderDispCnt & (1<<6)); + u32 fogshift = (RenderDispCnt >> 8) & 0xF; + u32 fogoffset = RenderFogOffset * 0x200; + + u32 fogR = (RenderFogColor << 1) & 0x3E; if (fogR) fogR++; + u32 fogG = (RenderFogColor >> 4) & 0x3E; if (fogG) fogG++; + u32 fogB = (RenderFogColor >> 9) & 0x3E; if (fogB) fogB++; + u32 fogA = (RenderFogColor >> 16) & 0x1F; + + for (int x = 0; x < 256; x++) + { + u32 pixeladdr = (y*256) + x; + + u32 attr = AttrBuffer[pixeladdr]; + if (!(attr & (1<<15))) continue; + + u32 z = DepthBuffer[pixeladdr]; + u32 densityid, densityfrac; + if (z < fogoffset) + { + densityid = 0; + densityfrac = 0; + } + else + { + z = (z - fogoffset) << fogshift; + densityid = z >> 19; + if (densityid >= 32) + { + densityid = 32; + densityfrac = 0; + } + else + densityfrac = z & 0x7FFFF; + } + + // checkme + u32 density = + ((RenderFogDensityTable[densityid] * (0x80000-densityfrac)) + + (RenderFogDensityTable[densityid+1] * densityfrac)) >> 19; + if (density >= 127) density = 128; + + u32 srccolor = ColorBuffer[pixeladdr]; + u32 srcR = srccolor & 0x3F; + u32 srcG = (srccolor >> 8) & 0x3F; + u32 srcB = (srccolor >> 16) & 0x3F; + u32 srcA = (srccolor >> 24) & 0x1F; + + if (fogcolor) + { + srcR = ((fogR * density) + (srcR * (128-density))) >> 7; + srcG = ((fogG * density) + (srcG * (128-density))) >> 7; + srcB = ((fogB * density) + (srcB * (128-density))) >> 7; + } + + if (densityid > 0) + srcA = ((fogA * density) + (srcA * (128-density))) >> 7; + else + srcA = ((0x1F * density) + (srcA * (128-density))) >> 7; // checkme + + ColorBuffer[pixeladdr] = srcR | (srcG << 8) | (srcB << 16) | (srcA << 24); + } + } } void ClearBuffers() |