Improve interlace and OAM interlace support.

Interlace is now possible in every bg mode. OAM interlace no longer
forces global interlace and properly switches between odd and even
lines. Screen output can now be 256x448.
This commit is contained in:
OV2 2011-02-03 22:05:45 +01:00
parent 7c4d1566f7
commit 5e53e209b9
3 changed files with 59 additions and 83 deletions

96
gfx.cpp
View File

@ -329,9 +329,8 @@ void S9xStartScreenRefresh (void)
{
if (IPPU.RenderThisFrame)
{
if (GFX.DoInterlace && GFX.InterlaceFrame == 0)
GFX.InterlaceFrame = 1;
else
GFX.InterlaceFrame = !GFX.InterlaceFrame;
if (!GFX.DoInterlace || !GFX.InterlaceFrame)
{
if (!S9xInitUpdate())
{
@ -339,50 +338,45 @@ void S9xStartScreenRefresh (void)
return;
}
GFX.InterlaceFrame = 0;
if (GFX.DoInterlace)
GFX.DoInterlace--;
IPPU.MaxBrightness = PPU.Brightness;
IPPU.PseudoHires = Memory.FillRAM[0x2133] & 8;
if (PPU.BGMode == 5 || PPU.BGMode == 6)
{
IPPU.Interlace = Memory.FillRAM[0x2133] & 1;
IPPU.InterlaceOBJ = Memory.FillRAM[0x2133] & 2;
}
IPPU.Interlace = Memory.FillRAM[0x2133] & 1;
IPPU.InterlaceOBJ = Memory.FillRAM[0x2133] & 2;
IPPU.PseudoHires = Memory.FillRAM[0x2133] & 8;
if (Settings.SupportHiRes && (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.PseudoHires || IPPU.Interlace || IPPU.InterlaceOBJ))
if (Settings.SupportHiRes && (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.PseudoHires))
{
GFX.RealPPL = GFX.Pitch >> 1;
IPPU.DoubleWidthPixels = TRUE;
IPPU.RenderedScreenWidth = SNES_WIDTH << 1;
if (IPPU.Interlace || IPPU.InterlaceOBJ)
{
GFX.PPL = GFX.RealPPL << 1;
IPPU.DoubleHeightPixels = TRUE;
IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1;
GFX.DoInterlace++;
}
else
{
GFX.PPL = GFX.RealPPL;
IPPU.DoubleHeightPixels = FALSE;
IPPU.RenderedScreenHeight = PPU.ScreenHeight;
}
}
else
{
IPPU.DoubleWidthPixels = FALSE;
IPPU.DoubleHeightPixels = FALSE;
IPPU.RenderedScreenWidth = SNES_WIDTH;
IPPU.RenderedScreenHeight = PPU.ScreenHeight;
#ifdef USE_OPENGL
if (Settings.OpenGLEnable)
GFX.RealPPL = GFX.PPL = SNES_WIDTH;
GFX.RealPPL = SNES_WIDTH;
else
#endif
GFX.RealPPL = GFX.PPL = GFX.Pitch >> 1;
GFX.RealPPL = GFX.Pitch >> 1;
IPPU.DoubleWidthPixels = FALSE;
IPPU.RenderedScreenWidth = SNES_WIDTH;
}
if (Settings.SupportHiRes && IPPU.Interlace)
{
GFX.PPL = GFX.RealPPL << 1;
IPPU.DoubleHeightPixels = TRUE;
IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1;
GFX.DoInterlace++;
}
else
{
GFX.PPL = GFX.RealPPL;
IPPU.DoubleHeightPixels = FALSE;
IPPU.RenderedScreenHeight = PPU.ScreenHeight;
}
IPPU.RenderedFramesCount++;
@ -652,7 +646,7 @@ static inline void RenderScreen (bool8 sub)
void S9xUpdateScreen (void)
{
if (IPPU.OBJChanged)
if (IPPU.OBJChanged || IPPU.InterlaceOBJ)
SetupOBJ();
// XXX: Check ForceBlank? Or anything else?
@ -675,7 +669,7 @@ void S9xUpdateScreen (void)
if (Settings.SupportHiRes)
{
if (!IPPU.DoubleWidthPixels && (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.PseudoHires || IPPU.Interlace || IPPU.InterlaceOBJ))
if (!IPPU.DoubleWidthPixels && (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.PseudoHires))
{
#ifdef USE_OPENGL
if (Settings.OpenGLEnable && GFX.RealPPL == 256)
@ -714,7 +708,7 @@ void S9xUpdateScreen (void)
IPPU.RenderedScreenWidth = 512;
}
if (!IPPU.DoubleHeightPixels && (IPPU.Interlace || IPPU.InterlaceOBJ))
if (!IPPU.DoubleHeightPixels && IPPU.Interlace)
{
IPPU.DoubleHeightPixels = TRUE;
IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1;
@ -803,6 +797,8 @@ static void SetupOBJ (void)
int inc = IPPU.InterlaceOBJ ? 2 : 1;
int startline = (IPPU.InterlaceOBJ && GFX.InterlaceFrame) ? 1 : 0;
// OK, we have three cases here. Either there's no priority, priority is
// normal FirstSprite, or priority is FirstSprite+Y. The first two are
// easy, the last is somewhat more ... interesting. So we split them up.
@ -853,7 +849,7 @@ static void SetupOBJ (void)
else
GFX.OBJVisibleTiles[S] = GFX.OBJWidths[S] >> 3;
for (uint8 line = 0, Y = (uint8) (PPU.OBJ[S].VPos & 0xff); line < Height; Y++, line += inc)
for (uint8 line = startline, Y = (uint8) (PPU.OBJ[S].VPos & 0xff); line < Height; Y++, line += inc)
{
if (Y >= SNES_HEIGHT_EXTENDED)
continue;
@ -919,7 +915,7 @@ static void SetupOBJ (void)
else
GFX.OBJVisibleTiles[S] = GFX.OBJWidths[S] >> 3;
for (uint8 line = 0, Y = (uint8) (PPU.OBJ[S].VPos & 0xff); line < Height; Y++, line += inc)
for (uint8 line = startline, Y = (uint8) (PPU.OBJ[S].VPos & 0xff); line < Height; Y++, line += inc)
{
if (Y >= SNES_HEIGHT_EXTENDED)
continue;
@ -996,8 +992,6 @@ static void DrawOBJS (int D)
int BaseTile = (((GFX.OBJLines[Y].OBJ[I].Line << 1) + (PPU.OBJ[S].Name & 0xf0)) & 0xf0) | (PPU.OBJ[S].Name & 0x100) | (PPU.OBJ[S].Palette << 10);
int TileX = PPU.OBJ[S].Name & 0x0f;
int TileLine = (GFX.OBJLines[Y].OBJ[I].Line & 7) * 8;
if (IPPU.InterlaceOBJ)
TileLine >>= 1;
int TileInc = 1;
if (PPU.OBJ[S].HFlip)
@ -1090,6 +1084,7 @@ static void DrawBackground (int bg, uint8 Zh, uint8 Zl)
int OffsetMask = (BG.TileSizeH == 16) ? 0x3ff : 0x1ff;
int OffsetShift = (BG.TileSizeV == 16) ? 4 : 3;
int PixWidth = IPPU.DoubleWidthPixels ? 2 : 1;
bool8 HiresInterlace = IPPU.Interlace && IPPU.DoubleWidthPixels;
void (*DrawTile) (uint32, uint32, uint32, uint32);
void (*DrawClippedTile) (uint32, uint32, uint32, uint32, uint32, uint32);
@ -1111,10 +1106,10 @@ static void DrawBackground (int bg, uint8 Zh, uint8 Zl)
for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
{
uint32 Y2 = IPPU.Interlace ? Y * 2 + GFX.InterlaceFrame : Y;
uint32 VOffset = LineData[Y].BG[bg].VOffset + (IPPU.Interlace ? 1 : 0);
uint32 Y2 = HiresInterlace ? Y * 2 + GFX.InterlaceFrame : Y;
uint32 VOffset = LineData[Y].BG[bg].VOffset + (HiresInterlace ? 1 : 0);
uint32 HOffset = LineData[Y].BG[bg].HOffset;
int VirtAlign = ((Y2 + VOffset) & 7) >> (IPPU.Interlace ? 1 : 0);
int VirtAlign = ((Y2 + VOffset) & 7) >> (HiresInterlace ? 1 : 0);
for (Lines = 1; Lines < GFX.LinesPerTile - VirtAlign; Lines++)
{
@ -1306,6 +1301,7 @@ static void DrawBackgroundMosaic (int bg, uint8 Zh, uint8 Zl)
int OffsetMask = (BG.TileSizeH == 16) ? 0x3ff : 0x1ff;
int OffsetShift = (BG.TileSizeV == 16) ? 4 : 3;
int PixWidth = IPPU.DoubleWidthPixels ? 2 : 1;
bool8 HiresInterlace = IPPU.Interlace && IPPU.DoubleWidthPixels;
void (*DrawPix) (uint32, uint32, uint32, uint32, uint32, uint32);
@ -1322,15 +1318,15 @@ static void DrawBackgroundMosaic (int bg, uint8 Zh, uint8 Zl)
for (uint32 Y = GFX.StartY - MosaicStart; Y <= GFX.EndY; Y += PPU.Mosaic)
{
uint32 Y2 = IPPU.Interlace ? Y * 2 : Y;
uint32 VOffset = LineData[Y].BG[bg].VOffset + (IPPU.Interlace ? 1 : 0);
uint32 Y2 = HiresInterlace ? Y * 2 : Y;
uint32 VOffset = LineData[Y].BG[bg].VOffset + (HiresInterlace ? 1 : 0);
uint32 HOffset = LineData[Y].BG[bg].HOffset;
Lines = PPU.Mosaic - MosaicStart;
if (Y + MosaicStart + Lines > GFX.EndY)
Lines = GFX.EndY - Y - MosaicStart + 1;
int VirtAlign = (((Y2 + VOffset) & 7) >> (IPPU.Interlace ? 1 : 0)) << 3;
int VirtAlign = (((Y2 + VOffset) & 7) >> (HiresInterlace ? 1 : 0)) << 3;
uint32 t1, t2;
uint32 TilemapRow = (VOffset + Y2) >> OffsetShift;
@ -1485,6 +1481,7 @@ static void DrawBackgroundOffset (int bg, uint8 Zh, uint8 Zl, int VOffOff)
int Offset2Shift = (BG.OffsetSizeV == 16) ? 4 : 3;
int OffsetEnableMask = 0x2000 << bg;
int PixWidth = IPPU.DoubleWidthPixels ? 2 : 1;
bool8 HiresInterlace = IPPU.Interlace && IPPU.DoubleWidthPixels;
void (*DrawTile) (uint32, uint32, uint32, uint32);
void (*DrawClippedTile) (uint32, uint32, uint32, uint32, uint32, uint32);
@ -1506,7 +1503,7 @@ static void DrawBackgroundOffset (int bg, uint8 Zh, uint8 Zl, int VOffOff)
for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y++)
{
uint32 Y2 = IPPU.Interlace ? Y * 2 + GFX.InterlaceFrame : Y;
uint32 Y2 = HiresInterlace ? Y * 2 + GFX.InterlaceFrame : Y;
uint32 VOff = LineData[Y].BG[2].VOffset - 1;
uint32 HOff = LineData[Y].BG[2].HOffset;
uint32 HOffsetRow = VOff >> Offset2Shift;
@ -1593,11 +1590,11 @@ static void DrawBackgroundOffset (int bg, uint8 Zh, uint8 Zl, int VOffOff)
HOffset = LineHOffset;
}
if (IPPU.Interlace)
if (HiresInterlace)
VOffset++;
uint32 t1, t2;
int VirtAlign = (((Y2 + VOffset) & 7) >> (IPPU.Interlace ? 1 : 0)) << 3;
int VirtAlign = (((Y2 + VOffset) & 7) >> (HiresInterlace ? 1 : 0)) << 3;
int TilemapRow = (VOffset + Y2) >> OffsetShift;
BG.InterlaceLine = ((VOffset + Y2) & 1) << 3;
@ -1716,6 +1713,7 @@ static void DrawBackgroundOffsetMosaic (int bg, uint8 Zh, uint8 Zl, int VOffOff)
int Offset2Shift = (BG.OffsetSizeV == 16) ? 4 : 3;
int OffsetEnableMask = 0x2000 << bg;
int PixWidth = IPPU.DoubleWidthPixels ? 2 : 1;
bool8 HiresInterlace = IPPU.Interlace && IPPU.DoubleWidthPixels;
void (*DrawPix) (uint32, uint32, uint32, uint32, uint32, uint32);
@ -1732,7 +1730,7 @@ static void DrawBackgroundOffsetMosaic (int bg, uint8 Zh, uint8 Zl, int VOffOff)
for (uint32 Y = GFX.StartY - MosaicStart; Y <= GFX.EndY; Y += PPU.Mosaic)
{
uint32 Y2 = IPPU.Interlace ? Y * 2 : Y;
uint32 Y2 = HiresInterlace ? Y * 2 : Y;
uint32 VOff = LineData[Y].BG[2].VOffset - 1;
uint32 HOff = LineData[Y].BG[2].HOffset;
@ -1824,11 +1822,11 @@ static void DrawBackgroundOffsetMosaic (int bg, uint8 Zh, uint8 Zl, int VOffOff)
HOffset = LineHOffset;
}
if (IPPU.Interlace)
if (HiresInterlace)
VOffset++;
uint32 t1, t2;
int VirtAlign = (((Y2 + VOffset) & 7) >> (IPPU.Interlace ? 1 : 0)) << 3;
int VirtAlign = (((Y2 + VOffset) & 7) >> (HiresInterlace ? 1 : 0)) << 3;
int TilemapRow = (VOffset + Y2) >> OffsetShift;
BG.InterlaceLine = ((VOffset + Y2) & 1) << 3;

View File

@ -454,10 +454,7 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
PPU.BGMode = Byte & 7;
// BJ: BG3Priority only takes effect if BGMode == 1 and the bit is set
PPU.BG3Priority = ((Byte & 0x0f) == 0x09);
if (PPU.BGMode == 5 || PPU.BGMode == 6)
IPPU.Interlace = Memory.FillRAM[0x2133] & 1;
else
IPPU.Interlace = 0;
IPPU.Interlace = Memory.FillRAM[0x2133] & 1;
#ifdef DEBUGGER
missing.modes[PPU.BGMode] = 1;
#endif
@ -979,8 +976,7 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
FLUSH_REDRAW();
if ((Memory.FillRAM[0x2133] ^ Byte) & 2)
IPPU.OBJChanged = TRUE;
if (PPU.BGMode == 5 || PPU.BGMode == 6)
IPPU.Interlace = Byte & 1;
IPPU.Interlace = Byte & 1;
IPPU.InterlaceOBJ = Byte & 2;
}
#ifdef DEBUGGER

View File

@ -492,7 +492,10 @@ void S9xSelectTileRenderers (int BGMode, bool8 sub, bool8 obj)
M7M1 = PPU.BGMosaic[0] && PPU.Mosaic > 1;
M7M2 = PPU.BGMosaic[1] && PPU.Mosaic > 1;
if (!IPPU.DoubleWidthPixels)
bool8 interlace = obj ? FALSE : IPPU.Interlace;
bool8 hires = !sub && (BGMode == 5 || BGMode == 6 || IPPU.PseudoHires);
if (!IPPU.DoubleWidthPixels) // normal width
{
DT = Renderers_DrawTile16Normal1x1;
DCT = Renderers_DrawClippedTile16Normal1x1;
@ -502,31 +505,9 @@ void S9xSelectTileRenderers (int BGMode, bool8 sub, bool8 obj)
DM7BG2 = M7M2 ? Renderers_DrawMode7MosaicBG2Normal1x1 : Renderers_DrawMode7BG2Normal1x1;
GFX.LinesPerTile = 8;
}
else
else if(hires) // hires double width
{
bool8 hires, interlace;
if (obj) // OBJ
{
hires = (BGMode == 5 || BGMode == 6 || IPPU.PseudoHires);
interlace = IPPU.InterlaceOBJ;
}
else
if (BGMode == 5 || BGMode == 6)
{
hires = TRUE;
interlace = IPPU.Interlace;
}
else
{
hires = IPPU.PseudoHires;
interlace = FALSE;
}
if (sub)
hires = FALSE;
if (hires && interlace)
if (interlace)
{
DT = Renderers_DrawTile16HiresInterlace;
DCT = Renderers_DrawClippedTile16HiresInterlace;
@ -537,7 +518,6 @@ void S9xSelectTileRenderers (int BGMode, bool8 sub, bool8 obj)
GFX.LinesPerTile = 4;
}
else
if (hires)
{
DT = Renderers_DrawTile16Hires;
DCT = Renderers_DrawClippedTile16Hires;
@ -547,7 +527,9 @@ void S9xSelectTileRenderers (int BGMode, bool8 sub, bool8 obj)
DM7BG2 = M7M2 ? Renderers_DrawMode7MosaicBG2Hires : Renderers_DrawMode7BG2Hires;
GFX.LinesPerTile = 8;
}
else
}
else // normal double width
{
if (interlace)
{
DT = Renderers_DrawTile16Interlace;
@ -1435,7 +1417,7 @@ extern struct SLineMatrixData LineMatrixData[240];
#define DRAW_PIXEL(N, M) DRAW_PIXEL_N2x1(N, M)
#define NAME2 Interlace
// Third-level include: Get the Interlace renderers.
// Third-level include: Get the double width Interlace renderers.
#include "tile.cpp"