mirror of
https://github.com/ShadauxCat/CATSFC.git
synced 2025-04-02 10:41:47 -04:00
4195 lines
110 KiB
C++
4195 lines
110 KiB
C++
/*******************************************************************************
|
|
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
|
|
|
|
(c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and
|
|
Jerremy Koot (jkoot@snes9x.com)
|
|
|
|
(c) Copyright 2001 - 2004 John Weidman (jweidman@slip.net)
|
|
|
|
(c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net),
|
|
funkyass (funkyass@spam.shaw.ca),
|
|
Joel Yliluoma (http://iki.fi/bisqwit/)
|
|
Kris Bleakley (codeviolation@hotmail.com),
|
|
Matthew Kendora,
|
|
Nach (n-a-c-h@users.sourceforge.net),
|
|
Peter Bortas (peter@bortas.org) and
|
|
zones (kasumitokoduck@yahoo.com)
|
|
|
|
C4 x86 assembler and some C emulation code
|
|
(c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com),
|
|
_Demo_ (_demo_@zsnes.com), and Nach
|
|
|
|
C4 C++ code
|
|
(c) Copyright 2003 Brad Jorsch
|
|
|
|
DSP-1 emulator code
|
|
(c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson,
|
|
John Weidman, neviksti (neviksti@hotmail.com),
|
|
Kris Bleakley, Andreas Naive
|
|
|
|
DSP-2 emulator code
|
|
(c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and
|
|
Lord Nightmare (lord_nightmare@users.sourceforge.net
|
|
|
|
OBC1 emulator code
|
|
(c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and
|
|
Kris Bleakley
|
|
Ported from x86 assembler to C by sanmaiwashi
|
|
|
|
SPC7110 and RTC C++ emulator code
|
|
(c) Copyright 2002 Matthew Kendora with research by
|
|
zsKnight, John Weidman, and Dark Force
|
|
|
|
S-DD1 C emulator code
|
|
(c) Copyright 2003 Brad Jorsch with research by
|
|
Andreas Naive and John Weidman
|
|
|
|
S-RTC C emulator code
|
|
(c) Copyright 2001 John Weidman
|
|
|
|
ST010 C++ emulator code
|
|
(c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora
|
|
|
|
Super FX x86 assembler emulator code
|
|
(c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
|
|
|
|
Super FX C emulator code
|
|
(c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman
|
|
|
|
|
|
SH assembler code partly based on x86 assembler code
|
|
(c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
|
|
|
|
|
|
Specific ports contains the works of other authors. See headers in
|
|
individual files.
|
|
|
|
Snes9x homepage: http://www.snes9x.com
|
|
|
|
Permission to use, copy, modify and distribute Snes9x in both binary and
|
|
source form, for non-commercial purposes, is hereby granted without fee,
|
|
providing that this license information and copyright notice appear with
|
|
all copies and any derived work.
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event shall the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Snes9x is freeware for PERSONAL USE only. Commercial users should
|
|
seek permission of the copyright holders first. Commercial use includes
|
|
charging money for Snes9x or software derived from Snes9x.
|
|
|
|
The copyright holders request that bug fixes and improvements to the code
|
|
should be forwarded to them so everyone can benefit from the modifications
|
|
in future versions.
|
|
|
|
Super NES and Super Nintendo Entertainment System are trademarks of
|
|
Nintendo Co., Limited and its subsidiary companies.
|
|
*******************************************************************************/
|
|
|
|
#include "snes9x.h"
|
|
|
|
#include "memmap.h"
|
|
#include "ppu.h"
|
|
#include "cpuexec.h"
|
|
#include "display.h"
|
|
#include "gfx.h"
|
|
#include "apu.h"
|
|
#include "cheats.h"
|
|
#include "screenshot.h"
|
|
|
|
#define M7 19
|
|
#define M8 19
|
|
|
|
void output_png();
|
|
void ComputeClipWindows ();
|
|
static void S9xDisplayFrameRate ();
|
|
static void S9xDisplayString (const char *string);
|
|
|
|
extern uint8 BitShifts[8][4];
|
|
extern uint8 TileShifts[8][4];
|
|
extern uint8 PaletteShifts[8][4];
|
|
extern uint8 PaletteMasks[8][4];
|
|
extern uint8 Depths[8][4];
|
|
extern uint8 BGSizes [2];
|
|
|
|
extern NormalTileRenderer DrawTilePtr;
|
|
extern ClippedTileRenderer DrawClippedTilePtr;
|
|
extern NormalTileRenderer DrawHiResTilePtr;
|
|
extern ClippedTileRenderer DrawHiResClippedTilePtr;
|
|
extern LargePixelRenderer DrawLargePixelPtr;
|
|
|
|
extern struct SBG BG;
|
|
|
|
extern struct SLineData LineData[240];
|
|
extern struct SLineMatrixData LineMatrixData [240];
|
|
|
|
extern uint8 Mode7Depths [2];
|
|
|
|
#define CLIP_10_BIT_SIGNED(a) \
|
|
((a) & ((1 << 10) - 1)) + (((((a) & (1 << 13)) ^ (1 << 13)) - (1 << 13)) >> 3)
|
|
|
|
#define ON_MAIN(N) \
|
|
(GFX.r212c & (1 << (N)) && \
|
|
!(PPU.BG_Forced & (1 << (N))))
|
|
|
|
#define SUB_OR_ADD(N) \
|
|
(GFX.r2131 & (1 << (N)))
|
|
|
|
#define ON_SUB(N) \
|
|
((GFX.r2130 & 0x30) != 0x30 && \
|
|
(GFX.r2130 & 2) && \
|
|
(GFX.r212d & (1 << N)) && \
|
|
!(PPU.BG_Forced & (1 << (N))))
|
|
|
|
#define ANYTHING_ON_SUB \
|
|
((GFX.r2130 & 0x30) != 0x30 && \
|
|
(GFX.r2130 & 2) && \
|
|
(GFX.r212d & 0x1f))
|
|
|
|
#define ADD_OR_SUB_ON_ANYTHING \
|
|
(GFX.r2131 & 0x3f)
|
|
|
|
#define FIX_INTERLACE(SCREEN, DO_DEPTH, DEPTH) \
|
|
if (IPPU.DoubleHeightPixels && ((PPU.BGMode != 5 && PPU.BGMode != 6) || !IPPU.Interlace)) \
|
|
for (uint32 y = GFX.StartY; y <= GFX.EndY; y++) \
|
|
{ \
|
|
memmove (SCREEN + (y * 2 + 1) * GFX.Pitch2, \
|
|
SCREEN + y * 2 * GFX.Pitch2, \
|
|
GFX.Pitch2); \
|
|
if(DO_DEPTH){ \
|
|
memmove (DEPTH + (y * 2 + 1) * (GFX.PPLx2>>1), \
|
|
DEPTH + y * GFX.PPL, \
|
|
GFX.PPLx2>>1); \
|
|
} \
|
|
}
|
|
|
|
|
|
#define BLACK BUILD_PIXEL(0,0,0)
|
|
|
|
#ifndef FOREVER_16_BIT
|
|
void DrawTile (uint32 Tile, uint32 Offset, uint32 StartLine,
|
|
uint32 LineCount);
|
|
void DrawClippedTile (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Width,
|
|
uint32 StartLine, uint32 LineCount);
|
|
void DrawTileHalfWidth (uint32 Tile, uint32 Offset, uint32 StartLine,
|
|
uint32 LineCount);
|
|
void DrawClippedTileHalfWidth (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Width,
|
|
uint32 StartLine, uint32 LineCount);
|
|
void DrawTilex2 (uint32 Tile, uint32 Offset, uint32 StartLine,
|
|
uint32 LineCount);
|
|
void DrawClippedTilex2 (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Width,
|
|
uint32 StartLine, uint32 LineCount);
|
|
void DrawTilex2x2 (uint32 Tile, uint32 Offset, uint32 StartLine,
|
|
uint32 LineCount);
|
|
void DrawClippedTilex2x2 (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Width,
|
|
uint32 StartLine, uint32 LineCount);
|
|
void DrawLargePixel (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Pixels,
|
|
uint32 StartLine, uint32 LineCount);
|
|
void DrawLargePixelHalfWidth (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Pixels,
|
|
uint32 StartLine, uint32 LineCount);
|
|
#endif
|
|
|
|
void DrawTile16 (uint32 Tile, uint32 Offset, uint32 StartLine,
|
|
uint32 LineCount);
|
|
void DrawClippedTile16 (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Width,
|
|
uint32 StartLine, uint32 LineCount);
|
|
void DrawTile16HalfWidth (uint32 Tile, uint32 Offset, uint32 StartLine,
|
|
uint32 LineCount);
|
|
void DrawClippedTile16HalfWidth (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Width,
|
|
uint32 StartLine, uint32 LineCount);
|
|
void DrawTile16x2 (uint32 Tile, uint32 Offset, uint32 StartLine,
|
|
uint32 LineCount);
|
|
void DrawClippedTile16x2 (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Width,
|
|
uint32 StartLine, uint32 LineCount);
|
|
void DrawTile16x2x2 (uint32 Tile, uint32 Offset, uint32 StartLine,
|
|
uint32 LineCount);
|
|
void DrawClippedTile16x2x2 (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Width,
|
|
uint32 StartLine, uint32 LineCount);
|
|
void DrawLargePixel16 (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Pixels,
|
|
uint32 StartLine, uint32 LineCount);
|
|
void DrawLargePixel16HalfWidth (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Pixels,
|
|
uint32 StartLine, uint32 LineCount);
|
|
|
|
void DrawTile16Add (uint32 Tile, uint32 Offset, uint32 StartLine,
|
|
uint32 LineCount);
|
|
|
|
void DrawClippedTile16Add (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Width,
|
|
uint32 StartLine, uint32 LineCount);
|
|
|
|
void DrawTile16Add1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
|
|
uint32 LineCount);
|
|
|
|
void DrawClippedTile16Add1_2 (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Width,
|
|
uint32 StartLine, uint32 LineCount);
|
|
|
|
void DrawTile16FixedAdd1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
|
|
uint32 LineCount);
|
|
|
|
void DrawClippedTile16FixedAdd1_2 (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Width,
|
|
uint32 StartLine, uint32 LineCount);
|
|
|
|
void DrawTile16Sub (uint32 Tile, uint32 Offset, uint32 StartLine,
|
|
uint32 LineCount);
|
|
|
|
void DrawClippedTile16Sub (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Width,
|
|
uint32 StartLine, uint32 LineCount);
|
|
|
|
void DrawTile16Sub1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
|
|
uint32 LineCount);
|
|
|
|
void DrawClippedTile16Sub1_2 (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Width,
|
|
uint32 StartLine, uint32 LineCount);
|
|
|
|
void DrawTile16FixedSub1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
|
|
uint32 LineCount);
|
|
|
|
void DrawClippedTile16FixedSub1_2 (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Width,
|
|
uint32 StartLine, uint32 LineCount);
|
|
|
|
void DrawLargePixel16Add (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Pixels,
|
|
uint32 StartLine, uint32 LineCount);
|
|
|
|
void DrawLargePixel16Add1_2 (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Pixels,
|
|
uint32 StartLine, uint32 LineCount);
|
|
|
|
void DrawLargePixel16Sub (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Pixels,
|
|
uint32 StartLine, uint32 LineCount);
|
|
|
|
void DrawLargePixel16Sub1_2 (uint32 Tile, uint32 Offset,
|
|
uint32 StartPixel, uint32 Pixels,
|
|
uint32 StartLine, uint32 LineCount);
|
|
|
|
bool8 S9xGraphicsInit ()
|
|
{
|
|
register uint32 PixelOdd = 1;
|
|
register uint32 PixelEven = 2;
|
|
|
|
#ifdef GFX_MULTI_FORMAT
|
|
if (GFX.BuildPixel == NULL)
|
|
S9xSetRenderPixelFormat (RGB565);
|
|
#endif
|
|
|
|
for (uint8 bitshift = 0; bitshift < 4; bitshift++)
|
|
{
|
|
for (register int i = 0; i < 16; i++)
|
|
{
|
|
register uint32 h = 0;
|
|
register uint32 l = 0;
|
|
|
|
#if defined(LSB_FIRST)
|
|
if (i & 8)
|
|
h |= PixelOdd;
|
|
if (i & 4)
|
|
h |= PixelOdd << 8;
|
|
if (i & 2)
|
|
h |= PixelOdd << 16;
|
|
if (i & 1)
|
|
h |= PixelOdd << 24;
|
|
if (i & 8)
|
|
l |= PixelOdd;
|
|
if (i & 4)
|
|
l |= PixelOdd << 8;
|
|
if (i & 2)
|
|
l |= PixelOdd << 16;
|
|
if (i & 1)
|
|
l |= PixelOdd << 24;
|
|
#else
|
|
if (i & 8)
|
|
h |= (PixelOdd << 24);
|
|
if (i & 4)
|
|
h |= (PixelOdd << 16);
|
|
if (i & 2)
|
|
h |= (PixelOdd << 8);
|
|
if (i & 1)
|
|
h |= PixelOdd;
|
|
if (i & 8)
|
|
l |= (PixelOdd << 24);
|
|
if (i & 4)
|
|
l |= (PixelOdd << 16);
|
|
if (i & 2)
|
|
l |= (PixelOdd << 8);
|
|
if (i & 1)
|
|
l |= PixelOdd;
|
|
#endif
|
|
|
|
odd_high[bitshift][i] = h;
|
|
odd_low[bitshift][i] = l;
|
|
h = l = 0;
|
|
|
|
#if defined(LSB_FIRST)
|
|
if (i & 8)
|
|
h |= PixelEven;
|
|
if (i & 4)
|
|
h |= PixelEven << 8;
|
|
if (i & 2)
|
|
h |= PixelEven << 16;
|
|
if (i & 1)
|
|
h |= PixelEven << 24;
|
|
if (i & 8)
|
|
l |= PixelEven;
|
|
if (i & 4)
|
|
l |= PixelEven << 8;
|
|
if (i & 2)
|
|
l |= PixelEven << 16;
|
|
if (i & 1)
|
|
l |= PixelEven << 24;
|
|
#else
|
|
if (i & 8)
|
|
h |= (PixelEven << 24);
|
|
if (i & 4)
|
|
h |= (PixelEven << 16);
|
|
if (i & 2)
|
|
h |= (PixelEven << 8);
|
|
if (i & 1)
|
|
h |= PixelEven;
|
|
if (i & 8)
|
|
l |= (PixelEven << 24);
|
|
if (i & 4)
|
|
l |= (PixelEven << 16);
|
|
if (i & 2)
|
|
l |= (PixelEven << 8);
|
|
if (i & 1)
|
|
l |= PixelEven;
|
|
#endif
|
|
|
|
even_high[bitshift][i] = h;
|
|
even_low[bitshift][i] = l;
|
|
}
|
|
PixelEven <<= 2;
|
|
PixelOdd <<= 2;
|
|
}
|
|
|
|
GFX.RealPitch = GFX.Pitch2 = GFX.Pitch;
|
|
GFX.ZPitch = GFX.Pitch;
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.SixteenBit)
|
|
#endif
|
|
GFX.ZPitch >>= 1;
|
|
GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
|
|
GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
|
|
//GFX.InfoStringTimeout = 0;
|
|
//GFX.InfoString = NULL;
|
|
|
|
PPU.BG_Forced = 0;
|
|
IPPU.OBJChanged = TRUE;
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.Transparency)
|
|
Settings.SixteenBit = TRUE;
|
|
#endif
|
|
|
|
IPPU.DirectColourMapsNeedRebuild = TRUE;
|
|
GFX.PixSize = 1;
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.SixteenBit)
|
|
{
|
|
#endif
|
|
DrawTilePtr = DrawTile16;
|
|
DrawClippedTilePtr = DrawClippedTile16;
|
|
DrawLargePixelPtr = DrawLargePixel16;
|
|
if (Settings.SupportHiRes)
|
|
{
|
|
DrawHiResTilePtr= DrawTile16;
|
|
DrawHiResClippedTilePtr = DrawClippedTile16;
|
|
}
|
|
else
|
|
{
|
|
DrawHiResTilePtr= DrawTile16HalfWidth;
|
|
DrawHiResClippedTilePtr = DrawClippedTile16HalfWidth;
|
|
}
|
|
GFX.PPL = GFX.Pitch >> 1;
|
|
GFX.PPLx2 = GFX.Pitch;
|
|
#ifndef FOREVER_16_BIT
|
|
}
|
|
else
|
|
{
|
|
DrawTilePtr = DrawTile;
|
|
DrawClippedTilePtr = DrawClippedTile;
|
|
DrawLargePixelPtr = DrawLargePixel;
|
|
if (Settings.SupportHiRes)
|
|
{
|
|
DrawHiResTilePtr= DrawTile;
|
|
DrawHiResClippedTilePtr = DrawClippedTile;
|
|
}
|
|
else
|
|
{
|
|
DrawHiResTilePtr= DrawTileHalfWidth;
|
|
DrawHiResClippedTilePtr = DrawClippedTileHalfWidth;
|
|
}
|
|
GFX.PPL = GFX.Pitch;
|
|
GFX.PPLx2 = GFX.Pitch * 2;
|
|
}
|
|
#endif
|
|
S9xFixColourBrightness ();
|
|
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.SixteenBit)
|
|
{
|
|
#endif
|
|
if (!(GFX.X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
|
|
return (FALSE);
|
|
|
|
if (!(GFX.ZERO_OR_X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)) ||
|
|
!(GFX.ZERO = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
|
|
{
|
|
if (GFX.ZERO_OR_X2)
|
|
{
|
|
free ((char *) GFX.ZERO_OR_X2);
|
|
GFX.ZERO_OR_X2 = NULL;
|
|
}
|
|
if (GFX.X2)
|
|
{
|
|
free ((char *) GFX.X2);
|
|
GFX.X2 = NULL;
|
|
}
|
|
return (FALSE);
|
|
}
|
|
uint32 r, g, b;
|
|
|
|
// Build a lookup table that multiplies a packed RGB value by 2 with
|
|
// saturation.
|
|
for (r = 0; r <= MAX_RED; r++)
|
|
{
|
|
uint32 r2 = r << 1;
|
|
if (r2 > MAX_RED)
|
|
r2 = MAX_RED;
|
|
for (g = 0; g <= MAX_GREEN; g++)
|
|
{
|
|
uint32 g2 = g << 1;
|
|
if (g2 > MAX_GREEN)
|
|
g2 = MAX_GREEN;
|
|
for (b = 0; b <= MAX_BLUE; b++)
|
|
{
|
|
uint32 b2 = b << 1;
|
|
if (b2 > MAX_BLUE)
|
|
b2 = MAX_BLUE;
|
|
GFX.X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
|
|
GFX.X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
|
|
}
|
|
}
|
|
}
|
|
ZeroMemory (GFX.ZERO, 0x10000 * sizeof (uint16));
|
|
ZeroMemory (GFX.ZERO_OR_X2, 0x10000 * sizeof (uint16));
|
|
// Build a lookup table that if the top bit of the color value is zero
|
|
// then the value is zero, otherwise multiply the value by 2. Used by
|
|
// the color subtraction code.
|
|
|
|
#if defined(OLD_COLOUR_BLENDING)
|
|
for (r = 0; r <= MAX_RED; r++)
|
|
{
|
|
uint32 r2 = r;
|
|
if ((r2 & 0x10) == 0)
|
|
r2 = 0;
|
|
else
|
|
r2 = (r2 << 1) & MAX_RED;
|
|
|
|
for (g = 0; g <= MAX_GREEN; g++)
|
|
{
|
|
uint32 g2 = g;
|
|
if ((g2 & GREEN_HI_BIT) == 0)
|
|
g2 = 0;
|
|
else
|
|
g2 = (g2 << 1) & MAX_GREEN;
|
|
|
|
for (b = 0; b <= MAX_BLUE; b++)
|
|
{
|
|
uint32 b2 = b;
|
|
if ((b2 & 0x10) == 0)
|
|
b2 = 0;
|
|
else
|
|
b2 = (b2 << 1) & MAX_BLUE;
|
|
|
|
GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
|
|
GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
for (r = 0; r <= MAX_RED; r++)
|
|
{
|
|
uint32 r2 = r;
|
|
if ((r2 & 0x10) == 0)
|
|
r2 = 0;
|
|
else
|
|
r2 = (r2 << 1) & MAX_RED;
|
|
|
|
if (r2 == 0)
|
|
r2 = 1;
|
|
for (g = 0; g <= MAX_GREEN; g++)
|
|
{
|
|
uint32 g2 = g;
|
|
if ((g2 & GREEN_HI_BIT) == 0)
|
|
g2 = 0;
|
|
else
|
|
g2 = (g2 << 1) & MAX_GREEN;
|
|
|
|
if (g2 == 0)
|
|
g2 = 1;
|
|
for (b = 0; b <= MAX_BLUE; b++)
|
|
{
|
|
uint32 b2 = b;
|
|
if ((b2 & 0x10) == 0)
|
|
b2 = 0;
|
|
else
|
|
b2 = (b2 << 1) & MAX_BLUE;
|
|
|
|
if (b2 == 0)
|
|
b2 = 1;
|
|
GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
|
|
GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Build a lookup table that if the top bit of the color value is zero
|
|
// then the value is zero, otherwise its just the value.
|
|
for (r = 0; r <= MAX_RED; r++)
|
|
{
|
|
uint32 r2 = r;
|
|
if ((r2 & 0x10) == 0)
|
|
r2 = 0;
|
|
else
|
|
r2 &= ~0x10;
|
|
|
|
for (g = 0; g <= MAX_GREEN; g++)
|
|
{
|
|
uint32 g2 = g;
|
|
if ((g2 & GREEN_HI_BIT) == 0)
|
|
g2 = 0;
|
|
else
|
|
g2 &= ~GREEN_HI_BIT;
|
|
for (b = 0; b <= MAX_BLUE; b++)
|
|
{
|
|
uint32 b2 = b;
|
|
if ((b2 & 0x10) == 0)
|
|
b2 = 0;
|
|
else
|
|
b2 &= ~0x10;
|
|
|
|
GFX.ZERO [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
|
|
GFX.ZERO [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
|
|
}
|
|
}
|
|
}
|
|
#ifndef FOREVER_16_BIT
|
|
}
|
|
else
|
|
{
|
|
GFX.X2 = NULL;
|
|
GFX.ZERO_OR_X2 = NULL;
|
|
GFX.ZERO = NULL;
|
|
}
|
|
#endif
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
void S9xGraphicsDeinit (void)
|
|
{
|
|
// Free any memory allocated in S9xGraphicsInit
|
|
if (GFX.X2)
|
|
{
|
|
free ((char *) GFX.X2);
|
|
GFX.X2 = NULL;
|
|
}
|
|
if (GFX.ZERO_OR_X2)
|
|
{
|
|
free ((char *) GFX.ZERO_OR_X2);
|
|
GFX.ZERO_OR_X2 = NULL;
|
|
}
|
|
if (GFX.ZERO)
|
|
{
|
|
free ((char *) GFX.ZERO);
|
|
GFX.ZERO = NULL;
|
|
}
|
|
}
|
|
|
|
void S9xBuildDirectColourMaps ()
|
|
{
|
|
for (uint32 p = 0; p < 8; p++)
|
|
{
|
|
for (uint32 c = 0; c < 256; c++)
|
|
{
|
|
// XXX: Brightness
|
|
DirectColourMaps [p][c] = BUILD_PIXEL (((c & 7) << 2) | ((p & 1) << 1),
|
|
((c & 0x38) >> 1) | (p & 2),
|
|
((c & 0xc0) >> 3) | (p & 4));
|
|
}
|
|
}
|
|
IPPU.DirectColourMapsNeedRebuild = FALSE;
|
|
}
|
|
|
|
void S9xStartScreenRefresh ()
|
|
{
|
|
if (GFX.InfoStringTimeout > 0 && --GFX.InfoStringTimeout == 0)
|
|
GFX.InfoString = NULL;
|
|
|
|
if (IPPU.RenderThisFrame)
|
|
{
|
|
if (!S9xInitUpdate ())
|
|
{
|
|
IPPU.RenderThisFrame = FALSE;
|
|
return;
|
|
}
|
|
|
|
IPPU.RenderedFramesCount++;
|
|
IPPU.PreviousLine = IPPU.CurrentLine = 0;
|
|
IPPU.MaxBrightness = PPU.Brightness;
|
|
IPPU.LatchedBlanking = PPU.ForcedBlanking;
|
|
|
|
if(PPU.BGMode == 5 || PPU.BGMode == 6)
|
|
IPPU.Interlace = (Memory.FillRAM[0x2133] & 1);
|
|
if (Settings.SupportHiRes && (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.Interlace))
|
|
{
|
|
if (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.Interlace)
|
|
{
|
|
IPPU.RenderedScreenWidth = 512;
|
|
IPPU.DoubleWidthPixels = TRUE;
|
|
IPPU.HalfWidthPixels = FALSE;
|
|
}
|
|
else
|
|
{
|
|
IPPU.RenderedScreenWidth = 256;
|
|
IPPU.DoubleWidthPixels = FALSE;
|
|
IPPU.HalfWidthPixels = FALSE;
|
|
}
|
|
|
|
if (IPPU.Interlace)
|
|
{
|
|
IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1;
|
|
IPPU.DoubleHeightPixels = TRUE;
|
|
GFX.Pitch2 = GFX.RealPitch;
|
|
GFX.Pitch = GFX.RealPitch * 2;
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.SixteenBit)
|
|
#endif
|
|
GFX.PPL = GFX.PPLx2 = GFX.RealPitch;
|
|
#ifndef FOREVER_16_BIT
|
|
else
|
|
GFX.PPL = GFX.PPLx2 = GFX.RealPitch << 1;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
IPPU.RenderedScreenHeight = PPU.ScreenHeight;
|
|
GFX.Pitch2 = GFX.Pitch = GFX.RealPitch;
|
|
IPPU.DoubleHeightPixels = FALSE;
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.SixteenBit)
|
|
#endif
|
|
GFX.PPL = GFX.Pitch >> 1;
|
|
#ifndef FOREVER_16_BIT
|
|
else
|
|
GFX.PPL = GFX.Pitch;
|
|
#endif
|
|
GFX.PPLx2 = GFX.PPL << 1;
|
|
}
|
|
}
|
|
else if (!Settings.SupportHiRes && (PPU.BGMode == 5))
|
|
{
|
|
// Secret of Mana displays menus with mode 5.
|
|
// Make them readable.
|
|
IPPU.DoubleWidthPixels = FALSE;
|
|
IPPU.HalfWidthPixels = TRUE;
|
|
IPPU.DoubleHeightPixels = FALSE;
|
|
}
|
|
else
|
|
{
|
|
IPPU.RenderedScreenWidth = 256;
|
|
IPPU.RenderedScreenHeight = PPU.ScreenHeight;
|
|
IPPU.DoubleWidthPixels = FALSE;
|
|
IPPU.HalfWidthPixels = FALSE;
|
|
IPPU.DoubleHeightPixels = FALSE;
|
|
{
|
|
GFX.Pitch2 = GFX.Pitch = GFX.RealPitch;
|
|
GFX.PPL = GFX.PPLx2 >> 1;
|
|
GFX.ZPitch = GFX.RealPitch;
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.SixteenBit)
|
|
#endif
|
|
GFX.ZPitch >>= 1;
|
|
}
|
|
}
|
|
|
|
PPU.RecomputeClipWindows = TRUE;
|
|
GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
|
|
GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
|
|
}
|
|
|
|
if (++IPPU.FrameCount % Memory.ROMFramesPerSecond == 0)
|
|
{
|
|
IPPU.DisplayedRenderedFrameCount = IPPU.RenderedFramesCount;
|
|
IPPU.RenderedFramesCount = 0;
|
|
IPPU.FrameCount = 0;
|
|
}
|
|
}
|
|
|
|
void RenderLine (uint8 C)
|
|
{
|
|
if (IPPU.RenderThisFrame)
|
|
{
|
|
LineData[C].BG[0].VOffset = PPU.BG[0].VOffset + 1;
|
|
LineData[C].BG[0].HOffset = PPU.BG[0].HOffset;
|
|
LineData[C].BG[1].VOffset = PPU.BG[1].VOffset + 1;
|
|
LineData[C].BG[1].HOffset = PPU.BG[1].HOffset;
|
|
|
|
if (PPU.BGMode == 7)
|
|
{
|
|
struct SLineMatrixData *p = &LineMatrixData [C];
|
|
p->MatrixA = PPU.MatrixA;
|
|
p->MatrixB = PPU.MatrixB;
|
|
p->MatrixC = PPU.MatrixC;
|
|
p->MatrixD = PPU.MatrixD;
|
|
p->CentreX = PPU.CentreX;
|
|
p->CentreY = PPU.CentreY;
|
|
}
|
|
else
|
|
{
|
|
if (Settings.StarfoxHack && PPU.BG[2].VOffset == 0 &&
|
|
PPU.BG[2].HOffset == 0xe000)
|
|
{
|
|
LineData[C].BG[2].VOffset = 0xe1;
|
|
LineData[C].BG[2].HOffset = 0;
|
|
}
|
|
else
|
|
{
|
|
LineData[C].BG[2].VOffset = PPU.BG[2].VOffset + 1;
|
|
LineData[C].BG[2].HOffset = PPU.BG[2].HOffset;
|
|
LineData[C].BG[3].VOffset = PPU.BG[3].VOffset + 1;
|
|
LineData[C].BG[3].HOffset = PPU.BG[3].HOffset;
|
|
}
|
|
}
|
|
IPPU.CurrentLine = C + 1;
|
|
} else {
|
|
/* if we're not rendering this frame, we still need to update this */
|
|
// XXX: Check ForceBlank? Or anything else?
|
|
if(IPPU.OBJChanged) S9xSetupOBJ();
|
|
PPU.RangeTimeOver |= GFX.OBJLines[C].RTOFlags;
|
|
}
|
|
}
|
|
|
|
void S9xEndScreenRefresh ()
|
|
{
|
|
IPPU.HDMAStarted = FALSE;
|
|
if (IPPU.RenderThisFrame)
|
|
{
|
|
FLUSH_REDRAW ();
|
|
if (IPPU.ColorsChanged)
|
|
{
|
|
uint32 saved = PPU.CGDATA[0];
|
|
#ifndef FOREVER_16_BIT
|
|
if (!Settings.SixteenBit)
|
|
{
|
|
// Hack for Super Mario World - to get its sky blue
|
|
// (It uses Fixed colour addition on the backdrop colour)
|
|
if (!(Memory.FillRAM [0x2131] & 0x80) && (Memory.FillRAM[0x2131] & 0x20) &&
|
|
(PPU.FixedColourRed || PPU.FixedColourGreen || PPU.FixedColourBlue))
|
|
{
|
|
PPU.CGDATA[0] = PPU.FixedColourRed | (PPU.FixedColourGreen << 5) |
|
|
(PPU.FixedColourBlue << 10);
|
|
}
|
|
}
|
|
#endif
|
|
IPPU.ColorsChanged = FALSE;
|
|
PPU.CGDATA[0] = saved;
|
|
}
|
|
|
|
GFX.Pitch = GFX.Pitch2 = GFX.RealPitch;
|
|
GFX.PPL = GFX.PPLx2 >> 1;
|
|
#if 0
|
|
//take screenshot here.
|
|
if(Settings.TakeScreenshot)
|
|
{
|
|
S9xDoScreenshot(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight);
|
|
cprintf("%s:%d\n", __FILE__, __LINE__);
|
|
}
|
|
if (Settings.DisplayFrameRate)
|
|
{
|
|
S9xDisplayFrameRate ();
|
|
cprintf("%s:%d\n", __FILE__, __LINE__);
|
|
}
|
|
if (GFX.InfoString)
|
|
{
|
|
S9xDisplayString (GFX.InfoString);
|
|
cprintf("%s:%d\n", __FILE__, __LINE__);
|
|
}
|
|
#endif
|
|
S9xDeinitUpdate (IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight,
|
|
#ifndef FOREVER_16_BIT
|
|
Settings.SixteenBit
|
|
#else
|
|
TRUE
|
|
#endif
|
|
);
|
|
}
|
|
|
|
S9xApplyCheats ();
|
|
#ifdef DEBUGGER
|
|
if (CPU.Flags & FRAME_ADVANCE_FLAG)
|
|
{
|
|
if (ICPU.FrameAdvanceCount)
|
|
{
|
|
ICPU.FrameAdvanceCount--;
|
|
IPPU.RenderThisFrame = TRUE;
|
|
IPPU.FrameSkip = 0;
|
|
}
|
|
else
|
|
{
|
|
CPU.Flags &= ~FRAME_ADVANCE_FLAG;
|
|
CPU.Flags |= DEBUG_MODE_FLAG;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (CPU.SRAMModified)
|
|
{
|
|
S9xAutoSaveSRAM ();
|
|
CPU.SRAMModified = FALSE;
|
|
/*if (!CPU.AutoSaveTimer)
|
|
{
|
|
if (!(CPU.AutoSaveTimer = Settings.AutoSaveDelay * Memory.ROMFramesPerSecond))
|
|
CPU.SRAMModified = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (!--CPU.AutoSaveTimer)
|
|
{
|
|
S9xAutoSaveSRAM ();
|
|
CPU.SRAMModified = FALSE;
|
|
}
|
|
}*/
|
|
}
|
|
|
|
}
|
|
|
|
void S9xSetInfoString (const char *string)
|
|
{
|
|
GFX.InfoString = string;
|
|
GFX.InfoStringTimeout = 120;
|
|
}
|
|
|
|
inline void SelectTileRenderer (bool8 normal)
|
|
{
|
|
if (normal)
|
|
{
|
|
if (IPPU.HalfWidthPixels)
|
|
{
|
|
DrawTilePtr = DrawTile16HalfWidth;
|
|
DrawClippedTilePtr = DrawClippedTile16HalfWidth;
|
|
DrawLargePixelPtr = DrawLargePixel16HalfWidth;
|
|
}
|
|
else
|
|
{
|
|
DrawTilePtr = DrawTile16;
|
|
DrawClippedTilePtr = DrawClippedTile16;
|
|
DrawLargePixelPtr = DrawLargePixel16;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (GFX.r2131 & 0xC0)
|
|
{
|
|
case 0x00:
|
|
DrawTilePtr = DrawTile16Add;
|
|
DrawClippedTilePtr = DrawClippedTile16Add;
|
|
DrawLargePixelPtr = DrawLargePixel16Add;
|
|
break;
|
|
case 0x40:
|
|
if (GFX.r2130 & 2)
|
|
{
|
|
DrawTilePtr = DrawTile16Add1_2;
|
|
DrawClippedTilePtr = DrawClippedTile16Add1_2;
|
|
}
|
|
else
|
|
{
|
|
// Fixed colour addition
|
|
DrawTilePtr = DrawTile16FixedAdd1_2;
|
|
DrawClippedTilePtr = DrawClippedTile16FixedAdd1_2;
|
|
}
|
|
DrawLargePixelPtr = DrawLargePixel16Add1_2;
|
|
break;
|
|
case 0x80:
|
|
DrawTilePtr = DrawTile16Sub;
|
|
DrawClippedTilePtr = DrawClippedTile16Sub;
|
|
DrawLargePixelPtr = DrawLargePixel16Sub;
|
|
break;
|
|
case 0xC0:
|
|
if (GFX.r2130 & 2)
|
|
{
|
|
DrawTilePtr = DrawTile16Sub1_2;
|
|
DrawClippedTilePtr = DrawClippedTile16Sub1_2;
|
|
}
|
|
else
|
|
{
|
|
// Fixed colour substraction
|
|
DrawTilePtr = DrawTile16FixedSub1_2;
|
|
DrawClippedTilePtr = DrawClippedTile16FixedSub1_2;
|
|
}
|
|
DrawLargePixelPtr = DrawLargePixel16Sub1_2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void S9xSetupOBJ ()
|
|
{
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) fprintf(stderr, "Entering SetupOBJS()\n");
|
|
#endif
|
|
int SmallWidth, SmallHeight;
|
|
int LargeWidth, LargeHeight;
|
|
|
|
switch (PPU.OBJSizeSelect)
|
|
{
|
|
case 0:
|
|
SmallWidth = SmallHeight = 8;
|
|
LargeWidth = LargeHeight = 16;
|
|
break;
|
|
case 1:
|
|
SmallWidth = SmallHeight = 8;
|
|
LargeWidth = LargeHeight = 32;
|
|
break;
|
|
case 2:
|
|
SmallWidth = SmallHeight = 8;
|
|
LargeWidth = LargeHeight = 64;
|
|
break;
|
|
case 3:
|
|
SmallWidth = SmallHeight = 16;
|
|
LargeWidth = LargeHeight = 32;
|
|
break;
|
|
case 4:
|
|
SmallWidth = SmallHeight = 16;
|
|
LargeWidth = LargeHeight = 64;
|
|
break;
|
|
default:
|
|
case 5:
|
|
SmallWidth = SmallHeight = 32;
|
|
LargeWidth = LargeHeight = 64;
|
|
break;
|
|
case 6:
|
|
SmallWidth = 16; SmallHeight = 32;
|
|
LargeWidth = 32; LargeHeight = 64;
|
|
break;
|
|
case 7:
|
|
SmallWidth = 16; SmallHeight = 32;
|
|
LargeWidth = LargeHeight = 32;
|
|
break;
|
|
}
|
|
if(IPPU.InterlaceSprites)
|
|
{
|
|
SmallHeight>>=1; LargeHeight>>=1;
|
|
}
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) fprintf(stderr, "Sizes are %dx%d and %dx%d\n", SmallWidth, SmallHeight, LargeWidth, LargeHeight);
|
|
#endif
|
|
|
|
/* 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. */
|
|
|
|
int Height;
|
|
uint8 S;
|
|
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) fprintf(stderr, "Priority rotation=%d, OAMAddr=%d -> ", PPU.OAMPriorityRotation, PPU.OAMAddr*2 | (PPU.OAMFlip&1));
|
|
#endif
|
|
if(!PPU.OAMPriorityRotation || !(PPU.OAMFlip&PPU.OAMAddr&1)){
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) fprintf(stderr, "normal FirstSprite = %02x\n", PPU.FirstSprite);
|
|
#endif
|
|
/* normal case */
|
|
uint8 LineOBJ[SNES_HEIGHT_EXTENDED];
|
|
memset(LineOBJ, 0, sizeof(LineOBJ));
|
|
for(int i=0; i<SNES_HEIGHT_EXTENDED; i++){
|
|
GFX.OBJLines[i].RTOFlags=0;
|
|
GFX.OBJLines[i].Tiles=34;
|
|
}
|
|
uint8 FirstSprite=PPU.FirstSprite;
|
|
S=FirstSprite;
|
|
do {
|
|
if(PPU.OBJ[S].Size){
|
|
GFX.OBJWidths[S]=LargeWidth; Height=LargeHeight;
|
|
} else {
|
|
GFX.OBJWidths[S]=SmallWidth; Height=SmallHeight;
|
|
}
|
|
int HPos=PPU.OBJ[S].HPos; if(HPos==-256) HPos=256;
|
|
if(HPos>-GFX.OBJWidths[S] && HPos<=256)
|
|
{
|
|
if(HPos<0){
|
|
GFX.OBJVisibleTiles[S]=(GFX.OBJWidths[S]+HPos+7)>>3;
|
|
} else if(HPos+GFX.OBJWidths[S]>=257){
|
|
GFX.OBJVisibleTiles[S]=(257-HPos+7)>>3;
|
|
} else {
|
|
GFX.OBJVisibleTiles[S]=GFX.OBJWidths[S]>>3;
|
|
}
|
|
for(uint8 line=0, Y=(uint8)(PPU.OBJ[S].VPos&0xff); line<Height; Y++, line++){
|
|
if(Y>=SNES_HEIGHT_EXTENDED) continue;
|
|
if(LineOBJ[Y]>=32){
|
|
GFX.OBJLines[Y].RTOFlags|=0x40;
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) fprintf(stderr, "%d: OBJ %02x ranged over\n", Y, S);
|
|
#endif
|
|
continue;
|
|
}
|
|
GFX.OBJLines[Y].Tiles-=GFX.OBJVisibleTiles[S];
|
|
if(GFX.OBJLines[Y].Tiles<0) GFX.OBJLines[Y].RTOFlags|=0x80;
|
|
GFX.OBJLines[Y].OBJ[LineOBJ[Y]].Sprite=S;
|
|
if(PPU.OBJ[S].VFlip){
|
|
// Yes, Width not Height. It so happens that the
|
|
// sprites with H=2*W flip as two WxW sprites.
|
|
GFX.OBJLines[Y].OBJ[LineOBJ[Y]].Line=line^(GFX.OBJWidths[S]-1);
|
|
} else {
|
|
GFX.OBJLines[Y].OBJ[LineOBJ[Y]].Line=line;
|
|
}
|
|
LineOBJ[Y]++;
|
|
}
|
|
}
|
|
S=(S+1)&0x7F;
|
|
} while(S!=FirstSprite);
|
|
|
|
for (int Y = 0; Y < SNES_HEIGHT_EXTENDED; Y++) {
|
|
if (LineOBJ[Y] < 32) // Add the sentinel
|
|
GFX.OBJLines[Y].OBJ[LineOBJ[Y]].Sprite = -1;
|
|
}
|
|
for(int Y=1; Y<SNES_HEIGHT_EXTENDED; Y++){
|
|
GFX.OBJLines[Y].RTOFlags |= GFX.OBJLines[Y-1].RTOFlags;
|
|
}
|
|
} else {
|
|
/* evil FirstSprite+Y case */
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) fprintf(stderr, "FirstSprite+Y\n");
|
|
#endif
|
|
|
|
/* First, find out which sprites are on which lines */
|
|
uint8 OBJOnLine[SNES_HEIGHT_EXTENDED][128];
|
|
// memset(OBJOnLine, 0, sizeof(OBJOnLine));
|
|
/* Hold on here, that's a lot of bytes to initialise at once!
|
|
* So we only initialise them per line, as needed. [Neb]
|
|
* Bonus: We can quickly avoid looping if a line has no OBJs.
|
|
*/
|
|
bool8 AnyOBJOnLine[SNES_HEIGHT_EXTENDED];
|
|
memset(AnyOBJOnLine, FALSE, sizeof(AnyOBJOnLine)); // better
|
|
|
|
for(S=0; S<128; S++){
|
|
if(PPU.OBJ[S].Size){
|
|
GFX.OBJWidths[S]=LargeWidth; Height=LargeHeight;
|
|
} else {
|
|
GFX.OBJWidths[S]=SmallWidth; Height=SmallHeight;
|
|
}
|
|
int HPos=PPU.OBJ[S].HPos; if(HPos==-256) HPos=256;
|
|
if(HPos>-GFX.OBJWidths[S] && HPos<=256)
|
|
{
|
|
if(HPos<0){
|
|
GFX.OBJVisibleTiles[S]=(GFX.OBJWidths[S]+HPos+7)>>3;
|
|
} else if(HPos+GFX.OBJWidths[S]>=257){
|
|
GFX.OBJVisibleTiles[S]=(257-HPos+7)>>3;
|
|
} else {
|
|
GFX.OBJVisibleTiles[S]=GFX.OBJWidths[S]>>3;
|
|
}
|
|
for(uint8 line=0, Y=(uint8)(PPU.OBJ[S].VPos&0xff); line<Height; Y++, line++){
|
|
if(Y>=SNES_HEIGHT_EXTENDED) continue;
|
|
if (!AnyOBJOnLine[Y]) {
|
|
memset(OBJOnLine[Y], 0, 128);
|
|
AnyOBJOnLine[Y] = TRUE;
|
|
}
|
|
if(PPU.OBJ[S].VFlip){
|
|
// Yes, Width not Height. It so happens that the
|
|
// sprites with H=2*W flip as two WxW sprites.
|
|
OBJOnLine[Y][S]=(line^(GFX.OBJWidths[S]-1)) | 0x80;
|
|
} else {
|
|
OBJOnLine[Y][S]=line | 0x80;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Now go through and pull out those OBJ that are actually visible. */
|
|
int j;
|
|
for(int Y=0; Y<SNES_HEIGHT_EXTENDED; Y++){
|
|
GFX.OBJLines[Y].RTOFlags=Y?0:GFX.OBJLines[Y-1].RTOFlags;
|
|
|
|
GFX.OBJLines[Y].Tiles=34;
|
|
j=0;
|
|
if (AnyOBJOnLine[Y]) {
|
|
uint8 FirstSprite=(PPU.FirstSprite+Y)&0x7F;
|
|
S=FirstSprite;
|
|
do {
|
|
if(OBJOnLine[Y][S]){
|
|
if(j>=32){
|
|
GFX.OBJLines[Y].RTOFlags|=0x40;
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) fprintf(stderr, "%d: OBJ %02x ranged over\n", Y, S);
|
|
#endif
|
|
break;
|
|
}
|
|
GFX.OBJLines[Y].Tiles-=GFX.OBJVisibleTiles[S];
|
|
if(GFX.OBJLines[Y].Tiles<0) GFX.OBJLines[Y].RTOFlags|=0x80;
|
|
GFX.OBJLines[Y].OBJ[j].Sprite=S;
|
|
GFX.OBJLines[Y].OBJ[j++].Line=OBJOnLine[Y][S]&~0x80;
|
|
}
|
|
S=(S+1)&0x7F;
|
|
} while(S!=FirstSprite);
|
|
}
|
|
if(j<32) GFX.OBJLines[Y].OBJ[j].Sprite=-1;
|
|
}
|
|
}
|
|
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) {
|
|
fprintf(stderr, "Sprites per line:\n");
|
|
for(int xxx=0; xxx<SNES_HEIGHT_EXTENDED; xxx++){
|
|
fprintf(stderr, "Line %d: RTO=%02x Tiles=%d", xxx, GFX.OBJLines[xxx].RTOFlags, 34-GFX.OBJLines[xxx].Tiles);
|
|
for(int j=0; j<32 && GFX.OBJLines[xxx].OBJ[j].Sprite>=0; j++){
|
|
fprintf(stderr, " %02x.%d", GFX.OBJLines[xxx].OBJ[j].Sprite, GFX.OBJLines[xxx].OBJ[j].Line);
|
|
}
|
|
fprintf(stderr, "\n");
|
|
}
|
|
|
|
fprintf(stderr, "Exiting SetupObj()\n");
|
|
}
|
|
#endif
|
|
|
|
IPPU.OBJChanged = FALSE;
|
|
}
|
|
|
|
static void DrawOBJS (bool8 OnMain = FALSE, uint8 D = 0)
|
|
{
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) fprintf(stderr, "Entering DrawOBJS() for %d-%d\n", GFX.StartY, GFX.EndY);
|
|
#endif
|
|
CHECK_SOUND();
|
|
|
|
BG.BitShift = 4;
|
|
BG.TileShift = 5;
|
|
BG.TileAddress = PPU.OBJNameBase;
|
|
BG.StartPalette = 128;
|
|
BG.PaletteShift = 4;
|
|
BG.PaletteMask = 7;
|
|
BG.Buffer = IPPU.TileCache [TILE_4BIT];
|
|
BG.Buffered = IPPU.TileCached [TILE_4BIT];
|
|
BG.NameSelect = PPU.OBJNameSelect;
|
|
BG.DirectColourMode = FALSE;
|
|
|
|
GFX.PixSize = 1;
|
|
|
|
struct {
|
|
uint16 Pos;
|
|
bool8 Value;
|
|
} Windows[7];
|
|
int clipcount = GFX.pCurrentClip->Count [4];
|
|
if (!clipcount){
|
|
Windows[0].Pos=0;
|
|
Windows[0].Value=TRUE;
|
|
Windows[1].Pos=256;
|
|
Windows[1].Value=FALSE;
|
|
Windows[2].Pos=1000;
|
|
Windows[2].Value=FALSE;
|
|
} else {
|
|
Windows[0].Pos=1000;
|
|
Windows[0].Value=FALSE;
|
|
for(int clip=0, i=1; clip<clipcount; clip++){
|
|
if(GFX.pCurrentClip->Right[clip][4]<=GFX.pCurrentClip->Left[clip][4]) continue;
|
|
int j;
|
|
for(j=0; j<i && Windows[j].Pos<GFX.pCurrentClip->Left[clip][4]; j++);
|
|
if(j<i && Windows[j].Pos==GFX.pCurrentClip->Left[clip][4]){
|
|
Windows[j].Value = TRUE;
|
|
} else {
|
|
if(j<i) memmove(&Windows[j+1], &Windows[j], sizeof(Windows[0])*(i-j));
|
|
Windows[j].Pos = GFX.pCurrentClip->Left[clip][4];
|
|
Windows[j].Value = TRUE;
|
|
i++;
|
|
}
|
|
for(j=0; j<i && Windows[j].Pos<GFX.pCurrentClip->Right[clip][4]; j++);
|
|
if(j>=i || Windows[j].Pos!=GFX.pCurrentClip->Right[clip][4]){
|
|
if(j<i) memmove(&Windows[j+1], &Windows[j], sizeof(Windows[0])*(i-j));
|
|
Windows[j].Pos = GFX.pCurrentClip->Right[clip][4];
|
|
Windows[j].Value = FALSE;
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) {
|
|
fprintf(stderr, "Windows:\n");
|
|
for(int xxx=0; xxx<6; xxx++){ fprintf(stderr, "%d: %d = %d\n", xxx, Windows[xxx].Pos, Windows[xxx].Value); }
|
|
}
|
|
#endif
|
|
|
|
if (Settings.SupportHiRes)
|
|
{
|
|
if (PPU.BGMode == 5 || PPU.BGMode == 6)
|
|
{
|
|
// Bah, OnMain is never used except to determine if calling
|
|
// SelectTileRenderer is necessary. So let's hack it to false here
|
|
// to stop SelectTileRenderer from being called when it causes
|
|
// problems.
|
|
OnMain = FALSE;
|
|
GFX.PixSize = 2;
|
|
if (IPPU.DoubleHeightPixels)
|
|
{
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.SixteenBit)
|
|
{
|
|
#endif
|
|
DrawTilePtr = DrawTile16x2x2;
|
|
DrawClippedTilePtr = DrawClippedTile16x2x2;
|
|
#ifndef FOREVER_16_BIT
|
|
}
|
|
else
|
|
{
|
|
DrawTilePtr = DrawTilex2x2;
|
|
DrawClippedTilePtr = DrawClippedTilex2x2;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.SixteenBit)
|
|
{
|
|
#endif
|
|
DrawTilePtr = DrawTile16x2;
|
|
DrawClippedTilePtr = DrawClippedTile16x2;
|
|
#ifndef FOREVER_16_BIT
|
|
}
|
|
else
|
|
{
|
|
DrawTilePtr = DrawTilex2;
|
|
DrawClippedTilePtr = DrawClippedTilex2;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.SixteenBit)
|
|
{
|
|
#endif
|
|
DrawTilePtr = DrawTile16;
|
|
DrawClippedTilePtr = DrawClippedTile16;
|
|
#ifndef FOREVER_16_BIT
|
|
}
|
|
else
|
|
{
|
|
DrawTilePtr = DrawTile;
|
|
DrawClippedTilePtr = DrawClippedTile;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else // if (!Settings.SupportHiRes)
|
|
{
|
|
if (PPU.BGMode == 5 || PPU.BGMode == 6)
|
|
{
|
|
// Bah, OnMain is never used except to determine if calling
|
|
// SelectTileRenderer is necessary. So let's hack it to false here
|
|
// to stop SelectTileRenderer from being called when it causes
|
|
// problems.
|
|
OnMain = FALSE;
|
|
}
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.SixteenBit)
|
|
{
|
|
#endif
|
|
DrawTilePtr = DrawTile16;
|
|
DrawClippedTilePtr = DrawClippedTile16;
|
|
#ifndef FOREVER_16_BIT
|
|
}
|
|
else
|
|
{
|
|
DrawTilePtr = DrawTile;
|
|
DrawClippedTilePtr = DrawClippedTile;
|
|
}
|
|
#endif
|
|
}
|
|
GFX.Z1 = D + 2;
|
|
|
|
for(uint32 Y=GFX.StartY, Offset=Y*GFX.PPL; Y<=GFX.EndY; Y++, Offset+=GFX.PPL){
|
|
#ifdef MK_DEBUG_RTO
|
|
bool8 Flag=0;
|
|
#endif
|
|
int I = 0;
|
|
#ifdef MK_DISABLE_TIME_OVER
|
|
int tiles=0;
|
|
#else
|
|
int tiles=GFX.OBJLines[Y].Tiles;
|
|
#endif
|
|
for (int S = GFX.OBJLines[Y].OBJ[I].Sprite; S >= 0 && I<32; S = GFX.OBJLines[Y].OBJ[++I].Sprite)
|
|
{
|
|
tiles+=GFX.OBJVisibleTiles[S];
|
|
if(tiles<=0){
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) {
|
|
if(!Flag){ Flag=1; fprintf(stderr, "Line %d:", Y); }
|
|
fprintf(stderr, " [%02x]", S);
|
|
}
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) {
|
|
if(!Flag){ Flag=1; fprintf(stderr, "Line %d:", Y); }
|
|
fprintf(stderr, " %02x", S);
|
|
}
|
|
#endif
|
|
|
|
if (OnMain && SUB_OR_ADD(4))
|
|
{
|
|
SelectTileRenderer (!GFX.Pseudo && PPU.OBJ [S].Palette < 4);
|
|
}
|
|
|
|
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;
|
|
int TileInc = 1;
|
|
|
|
if (PPU.OBJ[S].HFlip)
|
|
{
|
|
TileX = (TileX + (GFX.OBJWidths[S] >> 3) - 1) & 0x0f;
|
|
BaseTile |= H_FLIP;
|
|
TileInc = -1;
|
|
}
|
|
|
|
GFX.Z2 = (PPU.OBJ[S].Priority + 1) * 4 + D;
|
|
|
|
bool8 WinStat=TRUE;
|
|
int WinIdx=0, NextPos=-1000;
|
|
int X=PPU.OBJ[S].HPos; if(X==-256) X=256;
|
|
for(int t=tiles, O=Offset+X*GFX.PixSize; X<=256 && X<PPU.OBJ[S].HPos+GFX.OBJWidths[S]; TileX=(TileX+TileInc)&0x0f, X+=8, O+=8*GFX.PixSize){
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) {
|
|
if(X<-7) continue;
|
|
if((t-1)<0) fprintf(stderr, "-[%d]", 35-t);
|
|
else fprintf(stderr, "-%d", 35-t);
|
|
}
|
|
#endif
|
|
if(X<-7 || --t<0 || X==256) continue;
|
|
if(X>=NextPos){
|
|
for(; WinIdx<7 && Windows[WinIdx].Pos<=X; WinIdx++);
|
|
if(WinIdx==0) WinStat=FALSE;
|
|
else WinStat=Windows[WinIdx-1].Value;
|
|
NextPos=(WinIdx<7)?Windows[WinIdx].Pos:1000;
|
|
}
|
|
|
|
if(X+8<NextPos){
|
|
if(WinStat) (*DrawTilePtr) (BaseTile|TileX, O, TileLine, 1);
|
|
} else {
|
|
int x=X;
|
|
while(x<X+8){
|
|
if(WinStat) (*DrawClippedTilePtr) (BaseTile|TileX, O, x-X, NextPos-x, TileLine, 1);
|
|
x=NextPos;
|
|
for(; WinIdx<7 && Windows[WinIdx].Pos<=x; WinIdx++);
|
|
if(WinIdx==0) WinStat=FALSE;
|
|
else WinStat=Windows[WinIdx-1].Value;
|
|
NextPos=(WinIdx<7)?Windows[WinIdx].Pos:1000;
|
|
if(NextPos>X+8) NextPos=X+8;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) if(Flag) fprintf(stderr, "\n");
|
|
#endif
|
|
}
|
|
#ifdef MK_DEBUG_RTO
|
|
if(Settings.BGLayering) fprintf(stderr, "Exiting DrawOBJS() for %d-%d\n", GFX.StartY, GFX.EndY);
|
|
#endif
|
|
}
|
|
|
|
static void DrawBackgroundMosaic (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
|
|
{
|
|
CHECK_SOUND();
|
|
|
|
uint32 Tile;
|
|
uint16 *SC0;
|
|
uint16 *SC1;
|
|
uint16 *SC2;
|
|
uint16 *SC3;
|
|
uint8 depths [2] = {Z1, Z2};
|
|
|
|
if (BGMode == 0)
|
|
BG.StartPalette = bg << 5;
|
|
else
|
|
BG.StartPalette = 0;
|
|
|
|
SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
|
|
|
|
if (PPU.BG[bg].SCSize & 1)
|
|
SC1 = SC0 + 1024;
|
|
else
|
|
SC1 = SC0;
|
|
|
|
if(((uint8*)SC1-Memory.VRAM)>=0x10000)
|
|
SC1-=0x08000;
|
|
|
|
|
|
if (PPU.BG[bg].SCSize & 2)
|
|
SC2 = SC1 + 1024;
|
|
else
|
|
SC2 = SC0;
|
|
|
|
if(((uint8*)SC2-Memory.VRAM)>=0x10000)
|
|
SC2-=0x08000;
|
|
|
|
|
|
if (PPU.BG[bg].SCSize & 1)
|
|
SC3 = SC2 + 1024;
|
|
else
|
|
SC3 = SC2;
|
|
|
|
if(((uint8*)SC3-Memory.VRAM)>=0x10000)
|
|
SC3-=0x08000;
|
|
|
|
uint32 Lines;
|
|
uint32 OffsetMask;
|
|
uint32 OffsetShift;
|
|
|
|
if (BG.TileSize == 16)
|
|
{
|
|
OffsetMask = 0x3ff;
|
|
OffsetShift = 4;
|
|
}
|
|
else
|
|
{
|
|
OffsetMask = 0x1ff;
|
|
OffsetShift = 3;
|
|
}
|
|
|
|
int m5 = (BGMode == 5 || BGMode == 6) ? 1 : 0;
|
|
|
|
for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
|
|
{
|
|
uint32 VOffset = LineData [Y].BG[bg].VOffset;
|
|
uint32 HOffset = LineData [Y].BG[bg].HOffset;
|
|
uint32 MosaicOffset = Y % PPU.Mosaic;
|
|
|
|
for (Lines = 1; Lines < PPU.Mosaic - MosaicOffset; Lines++)
|
|
if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
|
|
(HOffset != LineData [Y + Lines].BG[bg].HOffset))
|
|
break;
|
|
|
|
uint32 MosaicLine = VOffset + Y - MosaicOffset;
|
|
|
|
if (Y + Lines > GFX.EndY)
|
|
Lines = GFX.EndY + 1 - Y;
|
|
uint32 VirtAlign = (MosaicLine & 7) << 3;
|
|
|
|
uint16 *b1;
|
|
uint16 *b2;
|
|
|
|
uint32 ScreenLine = MosaicLine >> OffsetShift;
|
|
uint32 Rem16 = MosaicLine & 15;
|
|
|
|
if (ScreenLine & 0x20)
|
|
b1 = SC2, b2 = SC3;
|
|
else
|
|
b1 = SC0, b2 = SC1;
|
|
|
|
b1 += (ScreenLine & 0x1f) << 5;
|
|
b2 += (ScreenLine & 0x1f) << 5;
|
|
uint16 *t;
|
|
uint32 Left = 0;
|
|
uint32 Right = 256 << m5;
|
|
|
|
HOffset <<= m5;
|
|
|
|
uint32 ClipCount = GFX.pCurrentClip->Count [bg];
|
|
uint32 HPos = HOffset;
|
|
uint32 PixWidth = (PPU.Mosaic << m5);
|
|
|
|
|
|
if (!ClipCount)
|
|
ClipCount = 1;
|
|
|
|
for (uint32 clip = 0; clip < ClipCount; clip++)
|
|
{
|
|
if (GFX.pCurrentClip->Count [bg])
|
|
{
|
|
Left = GFX.pCurrentClip->Left [clip][bg] << m5;
|
|
Right = GFX.pCurrentClip->Right [clip][bg] << m5;
|
|
|
|
uint32 r = Left % (PPU.Mosaic << m5);
|
|
HPos = HOffset + Left;
|
|
PixWidth = (PPU.Mosaic << m5) - r;
|
|
}
|
|
uint32 s = Y * GFX.PPL + Left * GFX.PixSize;
|
|
for (uint32 x = Left; x < Right; x += PixWidth,
|
|
s += (IPPU.HalfWidthPixels ? PixWidth >> 1 : PixWidth) * GFX.PixSize,
|
|
HPos += PixWidth, PixWidth = (PPU.Mosaic << m5))
|
|
{
|
|
uint32 Quot = (HPos & OffsetMask) >> 3;
|
|
|
|
if (x + PixWidth >= Right)
|
|
PixWidth = Right - x;
|
|
|
|
if (BG.TileSize == 8 && !m5)
|
|
{
|
|
if (Quot > 31)
|
|
t = b2 + (Quot & 0x1f);
|
|
else
|
|
t = b1 + Quot;
|
|
}
|
|
else
|
|
{
|
|
if (Quot > 63)
|
|
t = b2 + ((Quot >> 1) & 0x1f);
|
|
else
|
|
t = b1 + (Quot >> 1);
|
|
}
|
|
|
|
Tile = READ_2BYTES (t);
|
|
GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
|
|
|
|
// Draw tile...
|
|
if (BG.TileSize != 8)
|
|
{
|
|
if (Tile & H_FLIP)
|
|
{
|
|
// Horizontal flip, but what about vertical flip ?
|
|
if (Tile & V_FLIP)
|
|
{
|
|
// Both horzontal & vertical flip
|
|
if (Rem16 < 8)
|
|
{
|
|
(*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
|
|
HPos & 7, PixWidth,
|
|
VirtAlign, Lines);
|
|
}
|
|
else
|
|
{
|
|
(*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
|
|
HPos & 7, PixWidth,
|
|
VirtAlign, Lines);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Horizontal flip only
|
|
if (Rem16 > 7)
|
|
{
|
|
(*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
|
|
HPos & 7, PixWidth,
|
|
VirtAlign, Lines);
|
|
}
|
|
else
|
|
{
|
|
(*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
|
|
HPos & 7, PixWidth,
|
|
VirtAlign, Lines);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No horizontal flip, but is there a vertical flip ?
|
|
if (Tile & V_FLIP)
|
|
{
|
|
// Vertical flip only
|
|
if (Rem16 < 8)
|
|
{
|
|
(*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
|
|
HPos & 7, PixWidth,
|
|
VirtAlign, Lines);
|
|
}
|
|
else
|
|
{
|
|
(*DrawLargePixelPtr) (Tile + (Quot & 1), s,
|
|
HPos & 7, PixWidth,
|
|
VirtAlign, Lines);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Normal unflipped
|
|
if (Rem16 > 7)
|
|
{
|
|
(*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
|
|
HPos & 7, PixWidth,
|
|
VirtAlign, Lines);
|
|
}
|
|
else
|
|
{
|
|
(*DrawLargePixelPtr) (Tile + (Quot & 1), s,
|
|
HPos & 7, PixWidth,
|
|
VirtAlign, Lines);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
(*DrawLargePixelPtr) (Tile + (Quot & 1) * m5, s, HPos & 7, PixWidth,
|
|
VirtAlign, Lines);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void DrawBackgroundOffset (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
|
|
{
|
|
CHECK_SOUND();
|
|
|
|
uint32 Tile;
|
|
uint16 *SC0;
|
|
uint16 *SC1;
|
|
uint16 *SC2;
|
|
uint16 *SC3;
|
|
uint16 *BPS0;
|
|
uint16 *BPS1;
|
|
uint16 *BPS2;
|
|
uint16 *BPS3;
|
|
uint32 Width;
|
|
int VOffsetOffset = BGMode == 4 ? 0 : 32;
|
|
uint8 depths [2] = {Z1, Z2};
|
|
|
|
BG.StartPalette = 0;
|
|
|
|
BPS0 = (uint16 *) &Memory.VRAM[PPU.BG[2].SCBase << 1];
|
|
|
|
if (PPU.BG[2].SCSize & 1)
|
|
BPS1 = BPS0 + 1024;
|
|
else
|
|
BPS1 = BPS0;
|
|
|
|
if (PPU.BG[2].SCSize & 2)
|
|
BPS2 = BPS1 + 1024;
|
|
else
|
|
BPS2 = BPS0;
|
|
|
|
if (PPU.BG[2].SCSize & 1)
|
|
BPS3 = BPS2 + 1024;
|
|
else
|
|
BPS3 = BPS2;
|
|
|
|
SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
|
|
|
|
if (PPU.BG[bg].SCSize & 1)
|
|
SC1 = SC0 + 1024;
|
|
else
|
|
SC1 = SC0;
|
|
|
|
if(((uint8*)SC1-Memory.VRAM)>=0x10000)
|
|
SC1-=0x08000;
|
|
|
|
|
|
if (PPU.BG[bg].SCSize & 2)
|
|
SC2 = SC1 + 1024;
|
|
else
|
|
SC2 = SC0;
|
|
|
|
if(((uint8*)SC2-Memory.VRAM)>=0x10000)
|
|
SC2-=0x08000;
|
|
|
|
|
|
if (PPU.BG[bg].SCSize & 1)
|
|
SC3 = SC2 + 1024;
|
|
else
|
|
SC3 = SC2;
|
|
|
|
if(((uint8*)SC3-Memory.VRAM)>=0x10000)
|
|
SC3-=0x08000;
|
|
|
|
|
|
static const int Lines = 1;
|
|
int OffsetMask;
|
|
int OffsetShift;
|
|
int OffsetEnableMask = 1 << (bg + 13);
|
|
|
|
if (BG.TileSize == 16)
|
|
{
|
|
OffsetMask = 0x3ff;
|
|
OffsetShift = 4;
|
|
}
|
|
else
|
|
{
|
|
OffsetMask = 0x1ff;
|
|
OffsetShift = 3;
|
|
}
|
|
|
|
for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y++)
|
|
{
|
|
uint32 VOff = LineData [Y].BG[2].VOffset - 1;
|
|
// uint32 VOff = LineData [Y].BG[2].VOffset;
|
|
uint32 HOff = LineData [Y].BG[2].HOffset;
|
|
|
|
int VirtAlign;
|
|
int ScreenLine = VOff >> 3;
|
|
int t1;
|
|
int t2;
|
|
uint16 *s0;
|
|
uint16 *s1;
|
|
uint16 *s2;
|
|
|
|
if (ScreenLine & 0x20)
|
|
s1 = BPS2, s2 = BPS3;
|
|
else
|
|
s1 = BPS0, s2 = BPS1;
|
|
|
|
s1 += (ScreenLine & 0x1f) << 5;
|
|
s2 += (ScreenLine & 0x1f) << 5;
|
|
|
|
if(BGMode != 4)
|
|
{
|
|
if((ScreenLine & 0x1f) == 0x1f)
|
|
{
|
|
if(ScreenLine & 0x20)
|
|
VOffsetOffset = BPS0 - BPS2 - 0x1f*32;
|
|
else
|
|
VOffsetOffset = BPS2 - BPS0 - 0x1f*32;
|
|
}
|
|
else
|
|
{
|
|
VOffsetOffset = 32;
|
|
}
|
|
}
|
|
|
|
int clipcount = GFX.pCurrentClip->Count [bg];
|
|
if (!clipcount)
|
|
clipcount = 1;
|
|
|
|
for (int clip = 0; clip < clipcount; clip++)
|
|
{
|
|
uint32 Left;
|
|
uint32 Right;
|
|
|
|
if (!GFX.pCurrentClip->Count [bg])
|
|
{
|
|
Left = 0;
|
|
Right = 256;
|
|
}
|
|
else
|
|
{
|
|
Left = GFX.pCurrentClip->Left [clip][bg];
|
|
Right = GFX.pCurrentClip->Right [clip][bg];
|
|
|
|
if (Right <= Left)
|
|
continue;
|
|
}
|
|
|
|
uint32 VOffset;
|
|
uint32 HOffset;
|
|
//added:
|
|
uint32 LineHOffset=LineData [Y].BG[bg].HOffset;
|
|
|
|
uint32 Offset;
|
|
uint32 HPos;
|
|
uint32 Quot;
|
|
uint32 Count;
|
|
uint16 *t;
|
|
uint32 Quot2;
|
|
uint32 VCellOffset;
|
|
uint32 HCellOffset;
|
|
uint16 *b1;
|
|
uint16 *b2;
|
|
uint32 TotalCount = 0;
|
|
uint32 MaxCount = 8;
|
|
|
|
uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
|
|
bool8 left_hand_edge = (Left == 0);
|
|
Width = Right - Left;
|
|
|
|
if (Left & 7)
|
|
MaxCount = 8 - (Left & 7);
|
|
|
|
while (Left < Right)
|
|
{
|
|
if (left_hand_edge)
|
|
{
|
|
// The SNES offset-per-tile background mode has a
|
|
// hardware limitation that the offsets cannot be set
|
|
// for the tile at the left-hand edge of the screen.
|
|
VOffset = LineData [Y].BG[bg].VOffset;
|
|
|
|
//MKendora; use temp var to reduce memory accesses
|
|
//HOffset = LineData [Y].BG[bg].HOffset;
|
|
|
|
HOffset = LineHOffset;
|
|
//End MK
|
|
|
|
left_hand_edge = FALSE;
|
|
}
|
|
else
|
|
|
|
{
|
|
// All subsequent offset tile data is shifted left by one,
|
|
// hence the - 1 below.
|
|
|
|
Quot2 = ((HOff + Left - 1) & OffsetMask) >> 3;
|
|
|
|
if (Quot2 > 31)
|
|
s0 = s2 + (Quot2 & 0x1f);
|
|
else
|
|
s0 = s1 + Quot2;
|
|
|
|
HCellOffset = READ_2BYTES (s0);
|
|
|
|
if (BGMode == 4)
|
|
{
|
|
VOffset = LineData [Y].BG[bg].VOffset;
|
|
|
|
//MKendora another mem access hack
|
|
//HOffset = LineData [Y].BG[bg].HOffset;
|
|
HOffset=LineHOffset;
|
|
//end MK
|
|
|
|
if ((HCellOffset & OffsetEnableMask))
|
|
{
|
|
if (HCellOffset & 0x8000)
|
|
VOffset = HCellOffset + 1;
|
|
else
|
|
HOffset = HCellOffset;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VCellOffset = READ_2BYTES (s0 + VOffsetOffset);
|
|
if ((VCellOffset & OffsetEnableMask))
|
|
VOffset = VCellOffset + 1;
|
|
else
|
|
VOffset = LineData [Y].BG[bg].VOffset;
|
|
|
|
//MKendora Strike Gunner fix
|
|
if ((HCellOffset & OffsetEnableMask))
|
|
{
|
|
//HOffset= HCellOffset;
|
|
|
|
HOffset = (HCellOffset & ~7)|(LineHOffset&7);
|
|
//HOffset |= LineData [Y].BG[bg].HOffset&7;
|
|
}
|
|
else
|
|
HOffset=LineHOffset;
|
|
//HOffset = LineData [Y].BG[bg].HOffset -
|
|
//Settings.StrikeGunnerOffsetHack;
|
|
//HOffset &= (~7);
|
|
//end MK
|
|
}
|
|
}
|
|
VirtAlign = ((Y + VOffset) & 7) << 3;
|
|
ScreenLine = (VOffset + Y) >> OffsetShift;
|
|
|
|
if (((VOffset + Y) & 15) > 7)
|
|
{
|
|
t1 = 16;
|
|
t2 = 0;
|
|
}
|
|
else
|
|
{
|
|
t1 = 0;
|
|
t2 = 16;
|
|
}
|
|
|
|
if (ScreenLine & 0x20)
|
|
b1 = SC2, b2 = SC3;
|
|
else
|
|
b1 = SC0, b2 = SC1;
|
|
|
|
b1 += (ScreenLine & 0x1f) << 5;
|
|
b2 += (ScreenLine & 0x1f) << 5;
|
|
|
|
HPos = (HOffset + Left) & OffsetMask;
|
|
|
|
Quot = HPos >> 3;
|
|
|
|
if (BG.TileSize == 8)
|
|
{
|
|
if (Quot > 31)
|
|
t = b2 + (Quot & 0x1f);
|
|
else
|
|
t = b1 + Quot;
|
|
}
|
|
else
|
|
{
|
|
if (Quot > 63)
|
|
t = b2 + ((Quot >> 1) & 0x1f);
|
|
else
|
|
t = b1 + (Quot >> 1);
|
|
}
|
|
|
|
if (MaxCount + TotalCount > Width)
|
|
MaxCount = Width - TotalCount;
|
|
|
|
Offset = HPos & 7;
|
|
|
|
//Count =1;
|
|
Count = 8 - Offset;
|
|
if (Count > MaxCount)
|
|
Count = MaxCount;
|
|
|
|
s -= (IPPU.HalfWidthPixels ? Offset >> 1 : Offset) * GFX.PixSize;
|
|
Tile = READ_2BYTES(t);
|
|
GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
|
|
|
|
if (BG.TileSize == 8)
|
|
(*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign, Lines);
|
|
else
|
|
{
|
|
if (!(Tile & (V_FLIP | H_FLIP)))
|
|
{
|
|
// Normal, unflipped
|
|
(*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
|
|
s, Offset, Count, VirtAlign, Lines);
|
|
}
|
|
else
|
|
if (Tile & H_FLIP)
|
|
{
|
|
if (Tile & V_FLIP)
|
|
{
|
|
// H & V flip
|
|
(*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
|
|
s, Offset, Count, VirtAlign, Lines);
|
|
}
|
|
else
|
|
{
|
|
// H flip only
|
|
(*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
|
|
s, Offset, Count, VirtAlign, Lines);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// V flip only
|
|
(*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
|
|
s, Offset, Count, VirtAlign, Lines);
|
|
}
|
|
}
|
|
|
|
Left += Count;
|
|
TotalCount += Count;
|
|
s += (IPPU.HalfWidthPixels ? (Offset + Count) >> 1 : (Offset + Count)) * GFX.PixSize;
|
|
MaxCount = 8;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void DrawBackgroundMode5 (uint32 /* BGMODE */, uint32 bg, uint8 Z1, uint8 Z2)
|
|
{
|
|
CHECK_SOUND();
|
|
|
|
if(IPPU.Interlace)
|
|
{
|
|
GFX.Pitch = GFX.RealPitch;
|
|
GFX.PPL = GFX.PPLx2 >> 1;
|
|
}
|
|
GFX.PixSize = 1;
|
|
uint8 depths [2] = {Z1, Z2};
|
|
|
|
uint32 Tile;
|
|
uint16 *SC0;
|
|
uint16 *SC1;
|
|
uint16 *SC2;
|
|
uint16 *SC3;
|
|
uint32 Width;
|
|
|
|
BG.StartPalette = 0;
|
|
|
|
SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
|
|
|
|
if ((PPU.BG[bg].SCSize & 1))
|
|
SC1 = SC0 + 1024;
|
|
else
|
|
SC1 = SC0;
|
|
|
|
if((SC1-(unsigned short*)Memory.VRAM)>0x10000)
|
|
SC1=(uint16*)&Memory.VRAM[(((uint8*)SC1)-Memory.VRAM)%0x10000];
|
|
|
|
if ((PPU.BG[bg].SCSize & 2))
|
|
SC2 = SC1 + 1024;
|
|
else SC2 = SC0;
|
|
|
|
if(((uint8*)SC2-Memory.VRAM)>=0x10000)
|
|
SC2-=0x08000;
|
|
|
|
|
|
|
|
if ((PPU.BG[bg].SCSize & 1))
|
|
SC3 = SC2 + 1024;
|
|
else
|
|
SC3 = SC2;
|
|
|
|
if(((uint8*)SC3-Memory.VRAM)>=0x10000)
|
|
SC3-=0x08000;
|
|
|
|
|
|
|
|
int Lines;
|
|
int VOffsetMask;
|
|
int VOffsetShift;
|
|
|
|
if (BG.TileSize == 16)
|
|
{
|
|
VOffsetMask = 0x3ff;
|
|
VOffsetShift = 4;
|
|
}
|
|
else
|
|
{
|
|
VOffsetMask = 0x1ff;
|
|
VOffsetShift = 3;
|
|
}
|
|
int endy = IPPU.Interlace ? 1 + (GFX.EndY << 1) : GFX.EndY;
|
|
|
|
for (int Y = IPPU.Interlace ? GFX.StartY << 1 : GFX.StartY; Y <= endy; Y += Lines)
|
|
{
|
|
int y = IPPU.Interlace ? (Y >> 1) : Y;
|
|
uint32 VOffset = LineData [y].BG[bg].VOffset;
|
|
uint32 HOffset = LineData [y].BG[bg].HOffset;
|
|
int VirtAlign = (Y + VOffset) & 7;
|
|
|
|
for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
|
|
if ((VOffset != LineData [y + Lines].BG[bg].VOffset) ||
|
|
(HOffset != LineData [y + Lines].BG[bg].HOffset))
|
|
break;
|
|
|
|
HOffset <<= 1;
|
|
if (Y + Lines > endy)
|
|
Lines = endy + 1 - Y;
|
|
VirtAlign <<= 3;
|
|
|
|
int ScreenLine = (VOffset + Y) >> VOffsetShift;
|
|
int t1;
|
|
int t2;
|
|
if (((VOffset + Y) & 15) > 7)
|
|
{
|
|
t1 = 16;
|
|
t2 = 0;
|
|
}
|
|
else
|
|
{
|
|
t1 = 0;
|
|
t2 = 16;
|
|
}
|
|
uint16 *b1;
|
|
uint16 *b2;
|
|
|
|
if (ScreenLine & 0x20)
|
|
b1 = SC2, b2 = SC3;
|
|
else
|
|
b1 = SC0, b2 = SC1;
|
|
|
|
b1 += (ScreenLine & 0x1f) << 5;
|
|
b2 += (ScreenLine & 0x1f) << 5;
|
|
|
|
int clipcount = GFX.pCurrentClip->Count [bg];
|
|
if (!clipcount)
|
|
clipcount = 1;
|
|
for (int clip = 0; clip < clipcount; clip++)
|
|
{
|
|
int Left;
|
|
int Right;
|
|
|
|
if (!GFX.pCurrentClip->Count [bg])
|
|
{
|
|
Left = 0;
|
|
Right = 512;
|
|
}
|
|
else
|
|
{
|
|
Left = GFX.pCurrentClip->Left [clip][bg] * 2;
|
|
Right = GFX.pCurrentClip->Right [clip][bg] * 2;
|
|
|
|
if (Right <= Left)
|
|
continue;
|
|
}
|
|
|
|
uint32 s = (IPPU.HalfWidthPixels ? Left >> 1 : Left) * GFX.PixSize + Y * GFX.PPL;
|
|
uint32 HPos = (HOffset + Left * GFX.PixSize) & 0x3ff;
|
|
|
|
uint32 Quot = HPos >> 3;
|
|
uint32 Count = 0;
|
|
|
|
uint16 *t;
|
|
if (Quot > 63)
|
|
t = b2 + ((Quot >> 1) & 0x1f);
|
|
else
|
|
t = b1 + (Quot >> 1);
|
|
|
|
Width = Right - Left;
|
|
// Left hand edge clipped tile
|
|
if (HPos & 7)
|
|
{
|
|
int Offset = (HPos & 7);
|
|
Count = 8 - Offset;
|
|
if (Count > Width)
|
|
Count = Width;
|
|
s -= (IPPU.HalfWidthPixels ? Offset >> 1 : Offset);
|
|
Tile = READ_2BYTES (t);
|
|
GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
|
|
|
|
if (BG.TileSize == 8)
|
|
{
|
|
if (!(Tile & H_FLIP))
|
|
{
|
|
// Normal, unflipped
|
|
(*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
|
|
s, Offset, Count, VirtAlign, Lines);
|
|
}
|
|
else
|
|
{
|
|
// H flip
|
|
(*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
|
|
s, Offset, Count, VirtAlign, Lines);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(Tile & (V_FLIP | H_FLIP)))
|
|
{
|
|
// Normal, unflipped
|
|
(*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
|
|
s, Offset, Count, VirtAlign, Lines);
|
|
}
|
|
else
|
|
if (Tile & H_FLIP)
|
|
{
|
|
if (Tile & V_FLIP)
|
|
{
|
|
// H & V flip
|
|
(*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
|
|
s, Offset, Count, VirtAlign, Lines);
|
|
}
|
|
else
|
|
{
|
|
// H flip only
|
|
(*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
|
|
s, Offset, Count, VirtAlign, Lines);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// V flip only
|
|
(*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
|
|
s, Offset, Count, VirtAlign, Lines);
|
|
}
|
|
}
|
|
|
|
t += Quot & 1;
|
|
if (Quot == 63)
|
|
t = b2;
|
|
else if (Quot == 127)
|
|
t = b1;
|
|
Quot++;
|
|
s += (IPPU.HalfWidthPixels ? 4 : 8);
|
|
}
|
|
|
|
// Middle, unclipped tiles
|
|
Count = Width - Count;
|
|
int Middle = Count >> 3;
|
|
Count &= 7;
|
|
for (int C = Middle; C > 0; s += (IPPU.HalfWidthPixels ? 4 : 8), Quot++, C--)
|
|
{
|
|
Tile = READ_2BYTES(t);
|
|
GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
|
|
if (BG.TileSize == 8)
|
|
{
|
|
if (!(Tile & H_FLIP))
|
|
{
|
|
// Normal, unflipped
|
|
(*DrawHiResTilePtr) (Tile + (Quot & 1),
|
|
s, VirtAlign, Lines);
|
|
}
|
|
else
|
|
{
|
|
// H flip
|
|
(*DrawHiResTilePtr) (Tile + 1 - (Quot & 1),
|
|
s, VirtAlign, Lines);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(Tile & (V_FLIP | H_FLIP)))
|
|
{
|
|
// Normal, unflipped
|
|
(*DrawHiResTilePtr) (Tile + t1 + (Quot & 1),
|
|
s, VirtAlign, Lines);
|
|
}
|
|
else
|
|
if (Tile & H_FLIP)
|
|
{
|
|
if (Tile & V_FLIP)
|
|
{
|
|
// H & V flip
|
|
(*DrawHiResTilePtr) (Tile + t2 + 1 - (Quot & 1),
|
|
s, VirtAlign, Lines);
|
|
}
|
|
else
|
|
{
|
|
// H flip only
|
|
(*DrawHiResTilePtr) (Tile + t1 + 1 - (Quot & 1),
|
|
s, VirtAlign, Lines);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// V flip only
|
|
(*DrawHiResTilePtr) (Tile + t2 + (Quot & 1),
|
|
s, VirtAlign, Lines);
|
|
}
|
|
}
|
|
|
|
t += Quot & 1;
|
|
if (Quot == 63)
|
|
t = b2;
|
|
else
|
|
if (Quot == 127)
|
|
t = b1;
|
|
}
|
|
|
|
// Right-hand edge clipped tiles
|
|
if (Count)
|
|
{
|
|
Tile = READ_2BYTES(t);
|
|
GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
|
|
if (BG.TileSize == 8)
|
|
{
|
|
if (!(Tile & H_FLIP))
|
|
{
|
|
// Normal, unflipped
|
|
(*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
|
|
s, 0, Count, VirtAlign, Lines);
|
|
}
|
|
else
|
|
{
|
|
// H flip
|
|
(*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
|
|
s, 0, Count, VirtAlign, Lines);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(Tile & (V_FLIP | H_FLIP)))
|
|
{
|
|
// Normal, unflipped
|
|
(*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
|
|
s, 0, Count, VirtAlign, Lines);
|
|
}
|
|
else
|
|
if (Tile & H_FLIP)
|
|
{
|
|
if (Tile & V_FLIP)
|
|
{
|
|
// H & V flip
|
|
(*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
|
|
s, 0, Count, VirtAlign, Lines);
|
|
}
|
|
else
|
|
{
|
|
// H flip only
|
|
(*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
|
|
s, 0, Count, VirtAlign, Lines);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// V flip only
|
|
(*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
|
|
s, 0, Count, VirtAlign, Lines);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
GFX.Pitch = IPPU.DoubleHeightPixels ? GFX.RealPitch * 2 : GFX.RealPitch;
|
|
GFX.PPL = IPPU.DoubleHeightPixels ? GFX.PPLx2 : (GFX.PPLx2 >> 1);
|
|
|
|
}
|
|
|
|
static void DrawBackground (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
|
|
{
|
|
GFX.PixSize = 1;
|
|
|
|
BG.TileSize = BGSizes [PPU.BG[bg].BGSize];
|
|
BG.BitShift = BitShifts[BGMode][bg];
|
|
BG.TileShift = TileShifts[BGMode][bg];
|
|
BG.TileAddress = PPU.BG[bg].NameBase << 1;
|
|
BG.NameSelect = 0;
|
|
BG.Buffer = IPPU.TileCache [Depths [BGMode][bg]];
|
|
BG.Buffered = IPPU.TileCached [Depths [BGMode][bg]];
|
|
BG.PaletteShift = PaletteShifts[BGMode][bg];
|
|
BG.PaletteMask = PaletteMasks[BGMode][bg];
|
|
BG.DirectColourMode = (BGMode == 3 || BGMode == 4) && bg == 0 &&
|
|
(GFX.r2130 & 1);
|
|
|
|
if (PPU.BGMosaic [bg] && PPU.Mosaic > 1)
|
|
{
|
|
DrawBackgroundMosaic (BGMode, bg, Z1, Z2);
|
|
return;
|
|
|
|
}
|
|
switch (BGMode)
|
|
{
|
|
case 2:
|
|
case 4: // Used by Puzzle Bobble
|
|
DrawBackgroundOffset (BGMode, bg, Z1, Z2);
|
|
return;
|
|
|
|
case 5:
|
|
case 6: // XXX: is also offset per tile.
|
|
// if (Settings.SupportHiRes)
|
|
// {
|
|
if (!Settings.SupportHiRes)
|
|
SelectTileRenderer(TRUE /* normal */);
|
|
DrawBackgroundMode5 (BGMode, bg, Z1, Z2);
|
|
return;
|
|
// }
|
|
break;
|
|
}
|
|
CHECK_SOUND();
|
|
|
|
uint32 Tile;
|
|
uint16 *SC0;
|
|
uint16 *SC1;
|
|
uint16 *SC2;
|
|
uint16 *SC3;
|
|
uint32 Width;
|
|
uint8 depths [2] = {Z1, Z2};
|
|
|
|
if (BGMode == 0)
|
|
BG.StartPalette = bg << 5;
|
|
else BG.StartPalette = 0;
|
|
|
|
SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
|
|
|
|
if (PPU.BG[bg].SCSize & 1)
|
|
SC1 = SC0 + 1024;
|
|
else
|
|
SC1 = SC0;
|
|
|
|
if(SC1>=(unsigned short*)(Memory.VRAM+0x10000))
|
|
SC1=(uint16*)&Memory.VRAM[((uint8*)SC1-&Memory.VRAM[0])%0x10000];
|
|
|
|
if (PPU.BG[bg].SCSize & 2)
|
|
SC2 = SC1 + 1024;
|
|
else
|
|
SC2 = SC0;
|
|
|
|
if(((uint8*)SC2-Memory.VRAM)>=0x10000)
|
|
SC2-=0x08000;
|
|
|
|
if (PPU.BG[bg].SCSize & 1)
|
|
SC3 = SC2 + 1024;
|
|
else
|
|
SC3 = SC2;
|
|
|
|
if(((uint8*)SC3-Memory.VRAM)>=0x10000)
|
|
SC3-=0x08000;
|
|
|
|
|
|
|
|
int Lines;
|
|
int OffsetMask;
|
|
int OffsetShift;
|
|
|
|
if (BG.TileSize == 16)
|
|
{
|
|
OffsetMask = 0x3ff;
|
|
OffsetShift = 4;
|
|
}
|
|
else
|
|
{
|
|
OffsetMask = 0x1ff;
|
|
OffsetShift = 3;
|
|
}
|
|
|
|
for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
|
|
{
|
|
uint32 VOffset = LineData [Y].BG[bg].VOffset;
|
|
uint32 HOffset = LineData [Y].BG[bg].HOffset;
|
|
int VirtAlign = (Y + VOffset) & 7;
|
|
|
|
for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
|
|
if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
|
|
(HOffset != LineData [Y + Lines].BG[bg].HOffset))
|
|
break;
|
|
|
|
if (Y + Lines > GFX.EndY)
|
|
Lines = GFX.EndY + 1 - Y;
|
|
|
|
VirtAlign <<= 3;
|
|
|
|
uint32 ScreenLine = (VOffset + Y) >> OffsetShift;
|
|
uint32 t1;
|
|
uint32 t2;
|
|
if (((VOffset + Y) & 15) > 7)
|
|
{
|
|
t1 = 16;
|
|
t2 = 0;
|
|
}
|
|
else
|
|
{
|
|
t1 = 0;
|
|
t2 = 16;
|
|
}
|
|
uint16 *b1;
|
|
uint16 *b2;
|
|
|
|
if (ScreenLine & 0x20)
|
|
b1 = SC2, b2 = SC3;
|
|
else
|
|
b1 = SC0, b2 = SC1;
|
|
|
|
b1 += (ScreenLine & 0x1f) << 5;
|
|
b2 += (ScreenLine & 0x1f) << 5;
|
|
|
|
int clipcount = GFX.pCurrentClip->Count [bg];
|
|
if (!clipcount)
|
|
clipcount = 1;
|
|
for (int clip = 0; clip < clipcount; clip++)
|
|
{
|
|
uint32 Left;
|
|
uint32 Right;
|
|
|
|
if (!GFX.pCurrentClip->Count [bg])
|
|
{
|
|
Left = 0;
|
|
Right = 256;
|
|
}
|
|
else
|
|
{
|
|
Left = GFX.pCurrentClip->Left [clip][bg];
|
|
Right = GFX.pCurrentClip->Right [clip][bg];
|
|
|
|
if (Right <= Left)
|
|
continue;
|
|
}
|
|
|
|
uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
|
|
uint32 HPos = (HOffset + Left) & OffsetMask;
|
|
|
|
uint32 Quot = HPos >> 3;
|
|
uint32 Count = 0;
|
|
|
|
uint16 *t;
|
|
if (BG.TileSize == 8)
|
|
{
|
|
if (Quot > 31)
|
|
t = b2 + (Quot & 0x1f);
|
|
else
|
|
t = b1 + Quot;
|
|
}
|
|
else
|
|
{
|
|
if (Quot > 63)
|
|
t = b2 + ((Quot >> 1) & 0x1f);
|
|
else
|
|
t = b1 + (Quot >> 1);
|
|
}
|
|
|
|
Width = Right - Left;
|
|
// Left hand edge clipped tile
|
|
if (HPos & 7)
|
|
{
|
|
uint32 Offset = (HPos & 7);
|
|
Count = 8 - Offset;
|
|
if (Count > Width)
|
|
Count = Width;
|
|
s -= Offset * GFX.PixSize;
|
|
Tile = READ_2BYTES(t);
|
|
GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
|
|
|
|
if (BG.TileSize == 8)
|
|
{
|
|
(*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign,
|
|
Lines);
|
|
}
|
|
else
|
|
{
|
|
if (!(Tile & (V_FLIP | H_FLIP)))
|
|
{
|
|
// Normal, unflipped
|
|
(*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
|
|
s, Offset, Count, VirtAlign, Lines);
|
|
}
|
|
else
|
|
if (Tile & H_FLIP)
|
|
{
|
|
if (Tile & V_FLIP)
|
|
{
|
|
// H & V flip
|
|
(*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
|
|
s, Offset, Count, VirtAlign, Lines);
|
|
}
|
|
else
|
|
{
|
|
// H flip only
|
|
(*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
|
|
s, Offset, Count, VirtAlign, Lines);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// V flip only
|
|
(*DrawClippedTilePtr) (Tile + t2 + (Quot & 1), s,
|
|
Offset, Count, VirtAlign, Lines);
|
|
}
|
|
}
|
|
|
|
if (BG.TileSize == 8)
|
|
{
|
|
t++;
|
|
if (Quot == 31)
|
|
t = b2;
|
|
else if (Quot == 63)
|
|
t = b1;
|
|
}
|
|
else
|
|
{
|
|
t += Quot & 1;
|
|
if (Quot == 63)
|
|
t = b2;
|
|
else if (Quot == 127)
|
|
t = b1;
|
|
}
|
|
Quot++;
|
|
s += (IPPU.HalfWidthPixels ? 4 : 8) * GFX.PixSize;
|
|
}
|
|
|
|
// Middle, unclipped tiles
|
|
Count = Width - Count;
|
|
int Middle = Count >> 3;
|
|
Count &= 7;
|
|
for (int C = Middle; C > 0; s += (IPPU.HalfWidthPixels ? 4 : 8) * GFX.PixSize, Quot++, C--)
|
|
{
|
|
Tile = READ_2BYTES(t);
|
|
GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
|
|
|
|
if (BG.TileSize != 8)
|
|
{
|
|
if (Tile & H_FLIP)
|
|
{
|
|
// Horizontal flip, but what about vertical flip ?
|
|
if (Tile & V_FLIP)
|
|
{
|
|
// Both horzontal & vertical flip
|
|
(*DrawTilePtr) (Tile + t2 + 1 - (Quot & 1), s,
|
|
VirtAlign, Lines);
|
|
}
|
|
else
|
|
{
|
|
// Horizontal flip only
|
|
(*DrawTilePtr) (Tile + t1 + 1 - (Quot & 1), s,
|
|
VirtAlign, Lines);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No horizontal flip, but is there a vertical flip ?
|
|
if (Tile & V_FLIP)
|
|
{
|
|
// Vertical flip only
|
|
(*DrawTilePtr) (Tile + t2 + (Quot & 1), s,
|
|
VirtAlign, Lines);
|
|
}
|
|
else
|
|
{
|
|
// Normal unflipped
|
|
(*DrawTilePtr) (Tile + t1 + (Quot & 1), s,
|
|
VirtAlign, Lines);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(*DrawTilePtr) (Tile, s, VirtAlign, Lines);
|
|
}
|
|
|
|
if (BG.TileSize == 8)
|
|
{
|
|
t++;
|
|
if (Quot == 31)
|
|
t = b2;
|
|
else
|
|
if (Quot == 63)
|
|
t = b1;
|
|
}
|
|
else
|
|
{
|
|
t += Quot & 1;
|
|
if (Quot == 63)
|
|
t = b2;
|
|
else
|
|
if (Quot == 127)
|
|
t = b1;
|
|
}
|
|
}
|
|
// Right-hand edge clipped tiles
|
|
if (Count)
|
|
{
|
|
Tile = READ_2BYTES(t);
|
|
GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
|
|
|
|
if (BG.TileSize == 8)
|
|
(*DrawClippedTilePtr) (Tile, s, 0, Count, VirtAlign,
|
|
Lines);
|
|
else
|
|
{
|
|
if (!(Tile & (V_FLIP | H_FLIP)))
|
|
{
|
|
// Normal, unflipped
|
|
(*DrawClippedTilePtr) (Tile + t1 + (Quot & 1), s, 0,
|
|
Count, VirtAlign, Lines);
|
|
}
|
|
else if (Tile & H_FLIP)
|
|
{
|
|
if (Tile & V_FLIP)
|
|
{
|
|
// H & V flip
|
|
(*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
|
|
s, 0, Count, VirtAlign,
|
|
Lines);
|
|
}
|
|
else
|
|
{
|
|
// H flip only
|
|
(*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
|
|
s, 0, Count, VirtAlign,
|
|
Lines);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// V flip only
|
|
(*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
|
|
s, 0, Count, VirtAlign,
|
|
Lines);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#define RENDER_BACKGROUND_MODE7(TYPE,FUNC) \
|
|
uint16 *ScreenColors; \
|
|
CHECK_SOUND(); \
|
|
\
|
|
uint8 *VRAM1 = Memory.VRAM + 1; \
|
|
if (GFX.r2130 & 1) \
|
|
{ \
|
|
if (IPPU.DirectColourMapsNeedRebuild) \
|
|
S9xBuildDirectColourMaps (); \
|
|
ScreenColors = DirectColourMaps [0]; \
|
|
} \
|
|
else \
|
|
ScreenColors = IPPU.ScreenColors; \
|
|
\
|
|
int aa, cc; \
|
|
int dir; \
|
|
int startx, endx; \
|
|
uint32 Left = 0; \
|
|
uint32 Right = 256; \
|
|
uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
|
|
\
|
|
if (!ClipCount) \
|
|
ClipCount = 1; \
|
|
\
|
|
Screen += GFX.StartY * GFX.Pitch; \
|
|
uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
|
|
struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
|
|
\
|
|
for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
|
|
{ \
|
|
int yy; \
|
|
\
|
|
int32 HOffset = ((int32) LineData [Line].BG[0].HOffset << M7) >> M7; \
|
|
int32 VOffset = ((int32) LineData [Line].BG[0].VOffset << M7) >> M7; \
|
|
\
|
|
int32 CentreX = ((int32) l->CentreX << M7) >> M7; \
|
|
int32 CentreY = ((int32) l->CentreY << M7) >> M7; \
|
|
\
|
|
if (PPU.Mode7VFlip) \
|
|
yy = 255 - (int) Line; \
|
|
else \
|
|
yy = Line; \
|
|
\
|
|
yy += CLIP_10_BIT_SIGNED(VOffset - CentreY); \
|
|
\
|
|
int BB = l->MatrixB * yy + (CentreX << 8); \
|
|
int DD = l->MatrixD * yy + (CentreY << 8); \
|
|
\
|
|
for (uint32 clip = 0; clip < ClipCount; clip++) \
|
|
{ \
|
|
if (GFX.pCurrentClip->Count [bg]) \
|
|
{ \
|
|
Left = GFX.pCurrentClip->Left [clip][bg]; \
|
|
Right = GFX.pCurrentClip->Right [clip][bg]; \
|
|
if (Right <= Left) \
|
|
continue; \
|
|
} \
|
|
TYPE *p = (TYPE *) Screen + Left; \
|
|
uint8 *d = Depth + Left; \
|
|
\
|
|
if (PPU.Mode7HFlip) \
|
|
{ \
|
|
startx = Right - 1; \
|
|
endx = Left - 1; \
|
|
dir = -1; \
|
|
aa = -l->MatrixA; \
|
|
cc = -l->MatrixC; \
|
|
} \
|
|
else \
|
|
{ \
|
|
startx = Left; \
|
|
endx = Right; \
|
|
dir = 1; \
|
|
aa = l->MatrixA; \
|
|
cc = l->MatrixC; \
|
|
} \
|
|
\
|
|
int xx = startx + CLIP_10_BIT_SIGNED(HOffset - CentreX); \
|
|
int AA = l->MatrixA * xx; \
|
|
int CC = l->MatrixC * xx; \
|
|
\
|
|
if (!PPU.Mode7Repeat) \
|
|
{ \
|
|
for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
|
|
{ \
|
|
int X = ((AA + BB) >> 8) & 0x3ff; \
|
|
int Y = ((CC + DD) >> 8) & 0x3ff; \
|
|
uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
|
|
uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
|
|
GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
|
|
if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
|
|
{ \
|
|
*p = (FUNC); \
|
|
*d = GFX.Z1; \
|
|
} \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
|
|
{ \
|
|
int X = ((AA + BB) >> 8); \
|
|
int Y = ((CC + DD) >> 8); \
|
|
\
|
|
if (((X | Y) & ~0x3ff) == 0) \
|
|
{ \
|
|
uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
|
|
uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
|
|
GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
|
|
if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
|
|
{ \
|
|
*p = (FUNC); \
|
|
*d = GFX.Z1; \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
if (PPU.Mode7Repeat == 3) \
|
|
{ \
|
|
X = (x + HOffset) & 7; \
|
|
Y = (yy + CentreY) & 7; \
|
|
uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
|
|
GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
|
|
if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
|
|
{ \
|
|
*p = (FUNC); \
|
|
*d = GFX.Z1; \
|
|
} \
|
|
} \
|
|
} \
|
|
} \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
static void DrawBGMode7Background (uint8 *Screen, int bg)
|
|
{
|
|
RENDER_BACKGROUND_MODE7 (uint8, (uint8) (b & GFX.Mode7Mask))
|
|
}
|
|
|
|
static void DrawBGMode7Background16 (uint8 *Screen, int bg)
|
|
{
|
|
RENDER_BACKGROUND_MODE7 (uint16, ScreenColors [b & GFX.Mode7Mask]);
|
|
}
|
|
|
|
static void DrawBGMode7Background16Add (uint8 *Screen, int bg)
|
|
{
|
|
RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
|
|
(*(d + GFX.DepthDelta) != 1 ?
|
|
COLOR_ADD (ScreenColors [b & GFX.Mode7Mask],
|
|
p [GFX.Delta]) :
|
|
COLOR_ADD (ScreenColors [b & GFX.Mode7Mask],
|
|
GFX.FixedColour)) :
|
|
ScreenColors [b & GFX.Mode7Mask]);
|
|
}
|
|
|
|
static void DrawBGMode7Background16Add1_2 (uint8 *Screen, int bg)
|
|
{
|
|
RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
|
|
(*(d + GFX.DepthDelta) != 1 ?
|
|
COLOR_ADD1_2 (ScreenColors [b & GFX.Mode7Mask],
|
|
p [GFX.Delta]) :
|
|
COLOR_ADD (ScreenColors [b & GFX.Mode7Mask],
|
|
GFX.FixedColour)) :
|
|
ScreenColors [b & GFX.Mode7Mask]);
|
|
}
|
|
|
|
static void DrawBGMode7Background16Sub (uint8 *Screen, int bg)
|
|
{
|
|
RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
|
|
(*(d + GFX.DepthDelta) != 1 ?
|
|
COLOR_SUB (ScreenColors [b & GFX.Mode7Mask],
|
|
p [GFX.Delta]) :
|
|
COLOR_SUB (ScreenColors [b & GFX.Mode7Mask],
|
|
GFX.FixedColour)) :
|
|
ScreenColors [b & GFX.Mode7Mask]);
|
|
}
|
|
|
|
static void DrawBGMode7Background16Sub1_2 (uint8 *Screen, int bg)
|
|
{
|
|
RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
|
|
(*(d + GFX.DepthDelta) != 1 ?
|
|
COLOR_SUB1_2 (ScreenColors [b & GFX.Mode7Mask],
|
|
p [GFX.Delta]) :
|
|
COLOR_SUB (ScreenColors [b & GFX.Mode7Mask],
|
|
GFX.FixedColour)) :
|
|
ScreenColors [b & GFX.Mode7Mask]);
|
|
}
|
|
|
|
#define RENDER_BACKGROUND_MODE7_i(TYPE,FUNC,COLORFUNC) \
|
|
uint16 *ScreenColors; \
|
|
CHECK_SOUND(); \
|
|
\
|
|
uint8 *VRAM1 = Memory.VRAM + 1; \
|
|
if (GFX.r2130 & 1) \
|
|
{ \
|
|
if (IPPU.DirectColourMapsNeedRebuild) \
|
|
S9xBuildDirectColourMaps (); \
|
|
ScreenColors = DirectColourMaps [0]; \
|
|
} \
|
|
else \
|
|
ScreenColors = IPPU.ScreenColors; \
|
|
\
|
|
int aa, cc; \
|
|
int dir; \
|
|
int startx, endx; \
|
|
uint32 Left = 0; \
|
|
uint32 Right = 256; \
|
|
uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
|
|
\
|
|
if (!ClipCount) \
|
|
ClipCount = 1; \
|
|
\
|
|
Screen += GFX.StartY * GFX.Pitch; \
|
|
uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
|
|
struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
|
|
bool8 allowSimpleCase = FALSE; \
|
|
if (!l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100) \
|
|
&& !LineMatrixData[GFX.EndY].MatrixB && !LineMatrixData[GFX.EndY].MatrixC \
|
|
&& (LineMatrixData[GFX.EndY].MatrixA == 0x0100) && (LineMatrixData[GFX.EndY].MatrixD == 0x0100) \
|
|
) \
|
|
allowSimpleCase = TRUE; \
|
|
\
|
|
for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
|
|
{ \
|
|
int yy; \
|
|
\
|
|
int HOffset = ((int) LineData [Line].BG[0].HOffset << M7) >> M7; \
|
|
int VOffset = ((int) LineData [Line].BG[0].VOffset << M7) >> M7; \
|
|
\
|
|
int CentreX = ((int) l->CentreX << M7) >> M7; \
|
|
int CentreY = ((int) l->CentreY << M7) >> M7; \
|
|
\
|
|
if (PPU.Mode7VFlip) \
|
|
yy = 255 - (int) Line; \
|
|
else \
|
|
yy = Line; \
|
|
\
|
|
\
|
|
yy += CLIP_10_BIT_SIGNED(VOffset - CentreY); \
|
|
bool8 simpleCase = FALSE; \
|
|
int BB; \
|
|
int DD; \
|
|
/* Make a special case for the identity matrix, since it's a common case and */ \
|
|
/* can be done much more quickly without special effects */ \
|
|
if (allowSimpleCase && !l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100)) \
|
|
{ \
|
|
BB = CentreX << 8; \
|
|
DD = (yy + CentreY) << 8; \
|
|
simpleCase = TRUE; \
|
|
} \
|
|
else \
|
|
{ \
|
|
BB = l->MatrixB * yy + (CentreX << 8); \
|
|
DD = l->MatrixD * yy + (CentreY << 8); \
|
|
} \
|
|
\
|
|
for (uint32 clip = 0; clip < ClipCount; clip++) \
|
|
{ \
|
|
if (GFX.pCurrentClip->Count [bg]) \
|
|
{ \
|
|
Left = GFX.pCurrentClip->Left [clip][bg]; \
|
|
Right = GFX.pCurrentClip->Right [clip][bg]; \
|
|
if (Right <= Left) \
|
|
continue; \
|
|
} \
|
|
TYPE *p = (TYPE *) Screen + Left; \
|
|
uint8 *d = Depth + Left; \
|
|
\
|
|
if (PPU.Mode7HFlip) \
|
|
{ \
|
|
startx = Right - 1; \
|
|
endx = Left - 1; \
|
|
dir = -1; \
|
|
aa = -l->MatrixA; \
|
|
cc = -l->MatrixC; \
|
|
} \
|
|
else \
|
|
{ \
|
|
startx = Left; \
|
|
endx = Right; \
|
|
dir = 1; \
|
|
aa = l->MatrixA; \
|
|
cc = l->MatrixC; \
|
|
} \
|
|
int xx; \
|
|
\
|
|
xx = startx + CLIP_10_BIT_SIGNED(HOffset - CentreX); \
|
|
int AA, CC = 0; \
|
|
if (simpleCase) \
|
|
{ \
|
|
AA = xx << 8; \
|
|
} \
|
|
else \
|
|
{ \
|
|
AA = l->MatrixA * xx; \
|
|
CC = l->MatrixC * xx; \
|
|
} \
|
|
if (simpleCase) \
|
|
{ \
|
|
if (!PPU.Mode7Repeat) \
|
|
{ \
|
|
int x = startx; \
|
|
do \
|
|
{ \
|
|
int X = ((AA + BB) >> 8) & 0x3ff; \
|
|
int Y = (DD >> 8) & 0x3ff; \
|
|
uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
|
|
uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
|
|
GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
|
|
if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
|
|
{ \
|
|
TYPE theColor = COLORFUNC; \
|
|
*p = (FUNC) | ALPHA_BITS_MASK; \
|
|
*d = GFX.Z1; \
|
|
} \
|
|
AA += aa, p++, d++; \
|
|
x += dir; \
|
|
} while (x != endx); \
|
|
} \
|
|
else \
|
|
{ \
|
|
int x = startx; \
|
|
do { \
|
|
int X = (AA + BB) >> 8; \
|
|
int Y = DD >> 8; \
|
|
\
|
|
if (((X | Y) & ~0x3ff) == 0) \
|
|
{ \
|
|
uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
|
|
uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
|
|
GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
|
|
if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
|
|
{ \
|
|
TYPE theColor = COLORFUNC; \
|
|
*p = (FUNC) | ALPHA_BITS_MASK; \
|
|
*d = GFX.Z1; \
|
|
} \
|
|
} \
|
|
else if (PPU.Mode7Repeat == 3) \
|
|
{ \
|
|
X = (x + HOffset) & 7; \
|
|
Y = (yy + CentreY) & 7; \
|
|
uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
|
|
uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
|
|
GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
|
|
if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
|
|
{ \
|
|
TYPE theColor = COLORFUNC; \
|
|
*p = (FUNC) | ALPHA_BITS_MASK; \
|
|
*d = GFX.Z1; \
|
|
} \
|
|
} \
|
|
AA += aa; p++; d++; \
|
|
x += dir; \
|
|
} while (x != endx); \
|
|
} \
|
|
} \
|
|
else if (!PPU.Mode7Repeat) \
|
|
{ \
|
|
/* The bilinear interpolator: get the colors at the four points surrounding */ \
|
|
/* the location of one point in the _sampled_ image, and weight them according */ \
|
|
/* to their (city block) distance. It's very smooth, but blurry with "close up" */ \
|
|
/* points. */ \
|
|
\
|
|
/* 460 (slightly less than 2 source pixels per displayed pixel) is an educated */ \
|
|
/* guess for where bilinear filtering will become a poor method for averaging. */ \
|
|
/* (When reducing the image, the weighting used by a bilinear filter becomes */ \
|
|
/* arbitrary, and a simple mean is a better way to represent the source image.) */ \
|
|
/* You can think of this as a kind of mipmapping. */ \
|
|
if ((aa < 460 && aa > -460) && (cc < 460 && cc > -460)) \
|
|
{\
|
|
for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
|
|
{ \
|
|
uint32 xPos = AA + BB; \
|
|
uint32 xPix = xPos >> 8; \
|
|
uint32 yPos = CC + DD; \
|
|
uint32 yPix = yPos >> 8; \
|
|
uint32 X = xPix & 0x3ff; \
|
|
uint32 Y = yPix & 0x3ff; \
|
|
uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
|
|
uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
|
|
GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
|
|
if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
|
|
{ \
|
|
/* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
|
|
uint32 X10 = (xPix + dir) & 0x3ff; \
|
|
uint32 Y01 = (yPix + (PPU.Mode7VFlip?-1:1)) & 0x3ff; \
|
|
uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
|
|
uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
|
|
uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
|
|
uint32 p1 = COLORFUNC; \
|
|
p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
|
|
b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
|
|
uint32 p2 = COLORFUNC; \
|
|
p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
|
|
b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
|
|
uint32 p4 = COLORFUNC; \
|
|
p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
|
|
b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
|
|
uint32 p3 = COLORFUNC; \
|
|
p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
|
|
/* Xdel, Ydel: position (in 1/32nds) between the points */ \
|
|
uint32 Xdel = (xPos >> 3) & 0x1F; \
|
|
uint32 Ydel = (yPos >> 3) & 0x1F; \
|
|
uint32 XY = (Xdel*Ydel) >> 5; \
|
|
uint32 area1 = 0x20 + XY - Xdel - Ydel; \
|
|
uint32 area2 = Xdel - XY; \
|
|
uint32 area3 = Ydel - XY; \
|
|
uint32 area4 = XY; \
|
|
if(PPU.Mode7HFlip){ \
|
|
uint32 tmp=area1; area1=area2; area2=tmp; \
|
|
tmp=area3; area3=area4; area4=tmp; \
|
|
} \
|
|
if(PPU.Mode7VFlip){ \
|
|
uint32 tmp=area1; area1=area3; area3=tmp; \
|
|
tmp=area2; area2=area4; area4=tmp; \
|
|
} \
|
|
uint32 tempColor = ((area1 * p1) + \
|
|
(area2 * p2) + \
|
|
(area3 * p3) + \
|
|
(area4 * p4)) >> 5; \
|
|
TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
|
|
*p = (FUNC) | ALPHA_BITS_MASK; \
|
|
*d = GFX.Z1; \
|
|
} \
|
|
} \
|
|
} \
|
|
else \
|
|
/* The oversampling method: get the colors at four corners of a square */ \
|
|
/* in the _displayed_ image, and average them. It's sharp and clean, but */ \
|
|
/* gives the usual huge pixels when the source image gets "close." */ \
|
|
{ \
|
|
/* Find the dimensions of the square in the source image whose corners will be examined. */ \
|
|
uint32 aaDelX = aa >> 1; \
|
|
uint32 ccDelX = cc >> 1; \
|
|
uint32 bbDelY = l->MatrixB >> 1; \
|
|
uint32 ddDelY = l->MatrixD >> 1; \
|
|
/* Offset the location within the source image so that the four sampled points */ \
|
|
/* center around where the single point would otherwise have been drawn. */ \
|
|
BB -= (bbDelY >> 1); \
|
|
DD -= (ddDelY >> 1); \
|
|
AA -= (aaDelX >> 1); \
|
|
CC -= (ccDelX >> 1); \
|
|
uint32 BB10 = BB + aaDelX; \
|
|
uint32 BB01 = BB + bbDelY; \
|
|
uint32 BB11 = BB + aaDelX + bbDelY; \
|
|
uint32 DD10 = DD + ccDelX; \
|
|
uint32 DD01 = DD + ddDelY; \
|
|
uint32 DD11 = DD + ccDelX + ddDelY; \
|
|
for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
|
|
{ \
|
|
uint32 X = ((AA + BB) >> 8) & 0x3ff; \
|
|
uint32 Y = ((CC + DD) >> 8) & 0x3ff; \
|
|
uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
|
|
uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
|
|
GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
|
|
if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
|
|
{ \
|
|
/* X, Y, X10, Y10, etc. are the coordinates of the four pixels within the */ \
|
|
/* source image that we're going to examine. */ \
|
|
uint32 X10 = ((AA + BB10) >> 8) & 0x3ff; \
|
|
uint32 Y10 = ((CC + DD10) >> 8) & 0x3ff; \
|
|
uint32 X01 = ((AA + BB01) >> 8) & 0x3ff; \
|
|
uint32 Y01 = ((CC + DD01) >> 8) & 0x3ff; \
|
|
uint32 X11 = ((AA + BB11) >> 8) & 0x3ff; \
|
|
uint32 Y11 = ((CC + DD11) >> 8) & 0x3ff; \
|
|
uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y10 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
|
|
uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X01 >> 2) & ~1)] << 7); \
|
|
uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y11 & ~7) << 5) + ((X11 >> 2) & ~1)] << 7); \
|
|
TYPE p1 = COLORFUNC; \
|
|
b = *(TileData10 + ((Y10 & 7) << 4) + ((X10 & 7) << 1)); \
|
|
TYPE p2 = COLORFUNC; \
|
|
b = *(TileData01 + ((Y01 & 7) << 4) + ((X01 & 7) << 1)); \
|
|
TYPE p3 = COLORFUNC; \
|
|
b = *(TileData11 + ((Y11 & 7) << 4) + ((X11 & 7) << 1)); \
|
|
TYPE p4 = COLORFUNC; \
|
|
TYPE theColor = Q_INTERPOLATE(p1, p2, p3, p4); \
|
|
*p = (FUNC) | ALPHA_BITS_MASK; \
|
|
*d = GFX.Z1; \
|
|
} \
|
|
} \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
|
|
{ \
|
|
uint32 xPos = AA + BB; \
|
|
uint32 xPix = xPos >> 8; \
|
|
uint32 yPos = CC + DD; \
|
|
uint32 yPix = yPos >> 8; \
|
|
uint32 X = xPix; \
|
|
uint32 Y = yPix; \
|
|
\
|
|
\
|
|
if (((X | Y) & ~0x3ff) == 0) \
|
|
{ \
|
|
uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
|
|
uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
|
|
GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
|
|
if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
|
|
{ \
|
|
/* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
|
|
uint32 X10 = (xPix + dir) & 0x3ff; \
|
|
uint32 Y01 = (yPix + dir) & 0x3ff; \
|
|
uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
|
|
uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
|
|
uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
|
|
uint32 p1 = COLORFUNC; \
|
|
p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
|
|
b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
|
|
uint32 p2 = COLORFUNC; \
|
|
p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
|
|
b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
|
|
uint32 p4 = COLORFUNC; \
|
|
p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
|
|
b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
|
|
uint32 p3 = COLORFUNC; \
|
|
p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
|
|
/* Xdel, Ydel: position (in 1/32nds) between the points */ \
|
|
uint32 Xdel = (xPos >> 3) & 0x1F; \
|
|
uint32 Ydel = (yPos >> 3) & 0x1F; \
|
|
uint32 XY = (Xdel*Ydel) >> 5; \
|
|
uint32 area1 = 0x20 + XY - Xdel - Ydel; \
|
|
uint32 area2 = Xdel - XY; \
|
|
uint32 area3 = Ydel - XY; \
|
|
uint32 area4 = XY; \
|
|
uint32 tempColor = ((area1 * p1) + \
|
|
(area2 * p2) + \
|
|
(area3 * p3) + \
|
|
(area4 * p4)) >> 5; \
|
|
TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
|
|
*p = (FUNC) | ALPHA_BITS_MASK; \
|
|
*d = GFX.Z1; \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
if (PPU.Mode7Repeat == 3) \
|
|
{ \
|
|
X = (x + HOffset) & 7; \
|
|
Y = (yy + CentreY) & 7; \
|
|
uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
|
|
GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
|
|
if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
|
|
{ \
|
|
TYPE theColor = COLORFUNC; \
|
|
*p = (FUNC) | ALPHA_BITS_MASK; \
|
|
*d = GFX.Z1; \
|
|
} \
|
|
} \
|
|
} \
|
|
} \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
STATIC uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D)
|
|
{
|
|
register uint32 x = ((A >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
|
|
((B >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
|
|
((C >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
|
|
((D >> 2) & HIGH_BITS_SHIFTED_TWO_MASK);
|
|
register uint32 y = (A & TWO_LOW_BITS_MASK) +
|
|
(B & TWO_LOW_BITS_MASK) +
|
|
(C & TWO_LOW_BITS_MASK) +
|
|
(D & TWO_LOW_BITS_MASK);
|
|
y = (y>>2) & TWO_LOW_BITS_MASK;
|
|
return x+y;
|
|
}
|
|
|
|
static void DrawBGMode7Background16_i (uint8 *Screen, int bg)
|
|
{
|
|
RENDER_BACKGROUND_MODE7_i (uint16, theColor, (ScreenColors[b & GFX.Mode7Mask]));
|
|
}
|
|
|
|
static void DrawBGMode7Background16Add_i (uint8 *Screen, int bg)
|
|
{
|
|
RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
|
|
(*(d + GFX.DepthDelta) != 1 ?
|
|
(COLOR_ADD (theColor,
|
|
p [GFX.Delta])) :
|
|
(COLOR_ADD (theColor,
|
|
GFX.FixedColour))) :
|
|
theColor, (ScreenColors[b & GFX.Mode7Mask]));
|
|
}
|
|
|
|
static void DrawBGMode7Background16Add1_2_i (uint8 *Screen, int bg)
|
|
{
|
|
RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
|
|
(*(d + GFX.DepthDelta) != 1 ?
|
|
COLOR_ADD1_2 (theColor,
|
|
p [GFX.Delta]) :
|
|
COLOR_ADD (theColor,
|
|
GFX.FixedColour)) :
|
|
theColor, (ScreenColors[b & GFX.Mode7Mask]));
|
|
}
|
|
|
|
static void DrawBGMode7Background16Sub_i (uint8 *Screen, int bg)
|
|
{
|
|
RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
|
|
(*(d + GFX.DepthDelta) != 1 ?
|
|
COLOR_SUB (theColor,
|
|
p [GFX.Delta]) :
|
|
COLOR_SUB (theColor,
|
|
GFX.FixedColour)) :
|
|
theColor, (ScreenColors[b & GFX.Mode7Mask]));
|
|
}
|
|
|
|
static void DrawBGMode7Background16Sub1_2_i (uint8 *Screen, int bg)
|
|
{
|
|
RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
|
|
(*(d + GFX.DepthDelta) != 1 ?
|
|
COLOR_SUB1_2 (theColor,
|
|
p [GFX.Delta]) :
|
|
COLOR_SUB (theColor,
|
|
GFX.FixedColour)) :
|
|
theColor, (ScreenColors[b & GFX.Mode7Mask]));
|
|
}
|
|
|
|
#define _BUILD_SETUP(F) \
|
|
GFX.BuildPixel = BuildPixel##F; \
|
|
GFX.BuildPixel2 = BuildPixel2##F; \
|
|
GFX.DecomposePixel = DecomposePixel##F; \
|
|
RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_##F; \
|
|
GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_##F; \
|
|
BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_##F; \
|
|
RED_HI_BIT_MASK = RED_HI_BIT_MASK_##F; \
|
|
GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_##F; \
|
|
BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_##F; \
|
|
MAX_RED = MAX_RED_##F; \
|
|
MAX_GREEN = MAX_GREEN_##F; \
|
|
MAX_BLUE = MAX_BLUE_##F; \
|
|
GREEN_HI_BIT = ((MAX_GREEN_##F + 1) >> 1); \
|
|
SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_##F; \
|
|
RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_##F | \
|
|
GREEN_LOW_BIT_MASK_##F | \
|
|
BLUE_LOW_BIT_MASK_##F); \
|
|
RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_##F | \
|
|
GREEN_HI_BIT_MASK_##F | \
|
|
BLUE_HI_BIT_MASK_##F); \
|
|
RGB_HI_BITS_MASKx2 = ((RED_HI_BIT_MASK_##F | \
|
|
GREEN_HI_BIT_MASK_##F | \
|
|
BLUE_HI_BIT_MASK_##F) << 1); \
|
|
RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; \
|
|
FIRST_COLOR_MASK = FIRST_COLOR_MASK_##F; \
|
|
SECOND_COLOR_MASK = SECOND_COLOR_MASK_##F; \
|
|
THIRD_COLOR_MASK = THIRD_COLOR_MASK_##F; \
|
|
ALPHA_BITS_MASK = ALPHA_BITS_MASK_##F; \
|
|
FIRST_THIRD_COLOR_MASK = FIRST_COLOR_MASK | THIRD_COLOR_MASK; \
|
|
TWO_LOW_BITS_MASK = RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1); \
|
|
HIGH_BITS_SHIFTED_TWO_MASK = (( (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & \
|
|
~TWO_LOW_BITS_MASK ) >> 2);
|
|
|
|
static void RenderScreen (uint8 *Screen, bool8 sub, bool8 force_no_add, uint8 D)
|
|
{
|
|
bool8 BG0;
|
|
bool8 BG1;
|
|
bool8 BG2;
|
|
bool8 BG3;
|
|
bool8 OB;
|
|
|
|
GFX.S = Screen;
|
|
|
|
if (!sub)
|
|
{
|
|
GFX.pCurrentClip = &IPPU.Clip [0];
|
|
BG0 = ON_MAIN (0);
|
|
BG1 = ON_MAIN (1);
|
|
BG2 = ON_MAIN (2);
|
|
BG3 = ON_MAIN (3);
|
|
OB = ON_MAIN (4);
|
|
}
|
|
else
|
|
{
|
|
GFX.pCurrentClip = &IPPU.Clip [1];
|
|
BG0 = ON_SUB (0);
|
|
BG1 = ON_SUB (1);
|
|
BG2 = ON_SUB (2);
|
|
BG3 = ON_SUB (3);
|
|
OB = ON_SUB (4);
|
|
}
|
|
|
|
sub |= force_no_add;
|
|
|
|
switch (PPU.BGMode) {
|
|
case 0:
|
|
case 1:
|
|
if (OB)
|
|
{
|
|
SelectTileRenderer (sub || !SUB_OR_ADD(4));
|
|
DrawOBJS (!sub, D);
|
|
}
|
|
if (BG0)
|
|
{
|
|
SelectTileRenderer (sub || !SUB_OR_ADD(0));
|
|
DrawBackground (PPU.BGMode, 0, D + 10, D + 14);
|
|
}
|
|
if (BG1)
|
|
{
|
|
SelectTileRenderer (sub || !SUB_OR_ADD(1));
|
|
DrawBackground (PPU.BGMode, 1, D + 9, D + 13);
|
|
}
|
|
if (BG2)
|
|
{
|
|
SelectTileRenderer (sub || !SUB_OR_ADD(2));
|
|
DrawBackground (PPU.BGMode, 2, D + 3,
|
|
PPU.BG3Priority ? D + 17 : D + 6);
|
|
}
|
|
if (BG3 && PPU.BGMode == 0)
|
|
{
|
|
SelectTileRenderer (sub || !SUB_OR_ADD(3));
|
|
DrawBackground (PPU.BGMode, 3, D + 2, D + 5);
|
|
}
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
if (OB)
|
|
{
|
|
SelectTileRenderer (sub || !SUB_OR_ADD(4));
|
|
DrawOBJS (!sub, D);
|
|
}
|
|
if (BG0)
|
|
{
|
|
SelectTileRenderer (sub || !SUB_OR_ADD(0));
|
|
DrawBackground (PPU.BGMode, 0, D + 5, D + 13);
|
|
}
|
|
if (BG1 && PPU.BGMode != 6)
|
|
{
|
|
SelectTileRenderer (sub || !SUB_OR_ADD(1));
|
|
DrawBackground (PPU.BGMode, 1, D + 2, D + 9);
|
|
}
|
|
break;
|
|
case 7:
|
|
if (OB)
|
|
{
|
|
SelectTileRenderer (sub || !SUB_OR_ADD(4));
|
|
DrawOBJS (!sub, D);
|
|
}
|
|
if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
|
|
{
|
|
int bg;
|
|
|
|
if ((Memory.FillRAM [0x2133] & 0x40)&&BG1)
|
|
{
|
|
GFX.Mode7Mask = 0x7f;
|
|
GFX.Mode7PriorityMask = 0x80;
|
|
Mode7Depths [0] = (BG0?5:1) + D;
|
|
Mode7Depths [1] = 9 + D;
|
|
bg = 1;
|
|
}
|
|
else
|
|
{
|
|
GFX.Mode7Mask = 0xff;
|
|
GFX.Mode7PriorityMask = 0;
|
|
Mode7Depths [0] = 5 + D;
|
|
Mode7Depths [1] = 5 + D;
|
|
bg = 0;
|
|
}
|
|
if (sub || !SUB_OR_ADD(0))
|
|
{
|
|
if (!Settings.Mode7Interpolate)
|
|
DrawBGMode7Background16 (Screen, bg);
|
|
else
|
|
DrawBGMode7Background16_i (Screen, bg);
|
|
}
|
|
else
|
|
{
|
|
if (GFX.r2131 & 0x80)
|
|
{
|
|
if (GFX.r2131 & 0x40)
|
|
{
|
|
if (!Settings.Mode7Interpolate)
|
|
DrawBGMode7Background16Sub1_2 (Screen, bg);
|
|
else
|
|
DrawBGMode7Background16Sub1_2_i (Screen, bg);
|
|
}
|
|
else
|
|
{
|
|
if (!Settings.Mode7Interpolate)
|
|
DrawBGMode7Background16Sub (Screen, bg);
|
|
else
|
|
DrawBGMode7Background16Sub_i (Screen, bg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GFX.r2131 & 0x40)
|
|
{
|
|
if (!Settings.Mode7Interpolate)
|
|
DrawBGMode7Background16Add1_2 (Screen, bg);
|
|
else
|
|
DrawBGMode7Background16Add1_2_i (Screen, bg);
|
|
}
|
|
else
|
|
{
|
|
if (!Settings.Mode7Interpolate)
|
|
DrawBGMode7Background16Add (Screen, bg);
|
|
else
|
|
DrawBGMode7Background16Add_i (Screen, bg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#include "font.h"
|
|
|
|
void DisplayChar (uint8 *Screen, uint8 c)
|
|
{
|
|
int line = (((c & 0x7f) - 32) >> 4) * font_height;
|
|
int offset = (((c & 0x7f) - 32) & 15) * font_width;
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.SixteenBit)
|
|
{
|
|
#endif
|
|
int h, w;
|
|
uint16 *s = (uint16 *) Screen;
|
|
for (h = 0; h < font_height; h++, line++,
|
|
s += GFX.PPL - font_width)
|
|
{
|
|
for (w = 0; w < font_width; w++, s++)
|
|
{
|
|
uint8 p = font [line][offset + w];
|
|
|
|
if (p == '#')
|
|
{
|
|
/*
|
|
if(Memory.Hacked)
|
|
*s= BUILD_PIXEL(31,0,0);
|
|
else if(Memory.Iffy)
|
|
*s= BUILD_PIXEL(31,31,0);
|
|
else if(Memory.Iformat==1)
|
|
*s= BUILD_PIXEL(0,31,0);
|
|
else if(Memory.Iformat==2)
|
|
*s= BUILD_PIXEL(0,31,31);
|
|
else *s = 0xffff;
|
|
*/
|
|
*s=Settings.DisplayColor;
|
|
}
|
|
else
|
|
if (p == '.')
|
|
*s = BLACK;
|
|
}
|
|
}
|
|
#ifndef FOREVER_16_BIT
|
|
}
|
|
else
|
|
{
|
|
int h, w;
|
|
uint8 *s = Screen;
|
|
for (h = 0; h < font_height; h++, line++,
|
|
s += GFX.PPL - font_width)
|
|
{
|
|
for (w = 0; w < font_width; w++, s++)
|
|
{
|
|
uint8 p = font [line][offset + w];
|
|
|
|
if (p == '#')
|
|
*s = 255;
|
|
else
|
|
if (p == '.')
|
|
*s = BLACK;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void S9xDisplayFrameRate ()
|
|
{
|
|
uint8 *Screen = GFX.Screen + 2 +
|
|
(IPPU.RenderedScreenHeight - font_height - 1) * GFX.Pitch2;
|
|
char string [10];
|
|
int len = 5;
|
|
|
|
sprintf (string, "%02d/%02d", IPPU.DisplayedRenderedFrameCount,
|
|
(int) Memory.ROMFramesPerSecond);
|
|
|
|
int i;
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
DisplayChar (Screen, string [i]);
|
|
#ifndef FOREVER_16_BIT
|
|
Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) :
|
|
(font_width - 1);
|
|
#else
|
|
Screen += (font_width - 1) * sizeof (uint16);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void S9xDisplayString (const char *string)
|
|
{
|
|
uint8 *Screen = GFX.Screen + 2 +
|
|
(IPPU.RenderedScreenHeight - font_height * 5) * GFX.Pitch2;
|
|
int len = strlen (string);
|
|
int max_chars = IPPU.RenderedScreenWidth / (font_width - 1);
|
|
int char_count = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < len; i++, char_count++)
|
|
{
|
|
if (char_count >= max_chars || string [i] < 32)
|
|
{
|
|
#ifndef FOREVER_16_BIT
|
|
Screen -= Settings.SixteenBit ?
|
|
(font_width - 1) * sizeof (uint16) * max_chars :
|
|
(font_width - 1) * max_chars;
|
|
#else
|
|
Screen -= (font_width - 1) * max_chars * sizeof (uint16);
|
|
#endif
|
|
Screen += font_height * GFX.Pitch;
|
|
if (Screen >= GFX.Screen + GFX.Pitch * IPPU.RenderedScreenHeight)
|
|
break;
|
|
char_count -= max_chars;
|
|
}
|
|
if (string [i] < 32)
|
|
continue;
|
|
DisplayChar (Screen, string [i]);
|
|
#ifndef FOREVER_16_BIT
|
|
Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) :
|
|
(font_width - 1);
|
|
#else
|
|
Screen += (font_width - 1) * sizeof (uint16);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void S9xUpdateScreen ()
|
|
{
|
|
int32 x2 = 1;
|
|
|
|
GFX.S = GFX.Screen;
|
|
GFX.r2131 = Memory.FillRAM [0x2131];
|
|
GFX.r212c = Memory.FillRAM [0x212c];
|
|
GFX.r212d = Memory.FillRAM [0x212d];
|
|
GFX.r2130 = Memory.FillRAM [0x2130];
|
|
|
|
#ifdef JP_FIX
|
|
|
|
GFX.Pseudo = (Memory.FillRAM [0x2133] & 8) != 0 &&
|
|
(GFX.r212c & 15) != (GFX.r212d & 15) &&
|
|
(GFX.r2131 == 0x3f);
|
|
|
|
#else
|
|
|
|
GFX.Pseudo = (Memory.FillRAM [0x2133] & 8) != 0 &&
|
|
(GFX.r212c & 15) != (GFX.r212d & 15) &&
|
|
(GFX.r2131 & 0x3f) == 0;
|
|
|
|
#endif
|
|
|
|
if (IPPU.OBJChanged)
|
|
S9xSetupOBJ ();
|
|
|
|
if (PPU.RecomputeClipWindows)
|
|
{
|
|
ComputeClipWindows ();
|
|
PPU.RecomputeClipWindows = FALSE;
|
|
}
|
|
|
|
GFX.StartY = IPPU.PreviousLine;
|
|
if ((GFX.EndY = IPPU.CurrentLine - 1) >= PPU.ScreenHeight)
|
|
GFX.EndY = PPU.ScreenHeight - 1;
|
|
|
|
// XXX: Check ForceBlank? Or anything else?
|
|
PPU.RangeTimeOver |= GFX.OBJLines[GFX.EndY].RTOFlags;
|
|
|
|
uint32 starty = GFX.StartY;
|
|
uint32 endy = GFX.EndY;
|
|
|
|
if (Settings.SupportHiRes &&
|
|
(PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.Interlace || IPPU.DoubleHeightPixels))
|
|
{
|
|
if (PPU.BGMode == 5 || PPU.BGMode == 6|| IPPU.Interlace)
|
|
{
|
|
IPPU.RenderedScreenWidth = 512;
|
|
x2 = 2;
|
|
}
|
|
|
|
if (IPPU.DoubleHeightPixels)
|
|
{
|
|
starty = GFX.StartY * 2;
|
|
endy = GFX.EndY * 2 + 1;
|
|
}
|
|
|
|
if ((PPU.BGMode == 5 || PPU.BGMode == 6) && !IPPU.DoubleWidthPixels)
|
|
{
|
|
// The game has switched from lo-res to hi-res mode part way down
|
|
// the screen. Scale any existing lo-res pixels on screen
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.SixteenBit)
|
|
{
|
|
#endif
|
|
for (register uint32 y = 0; y < starty; y++)
|
|
{
|
|
register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + 255;
|
|
register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + 510;
|
|
|
|
for (register int x = 255; x >= 0; x--, p--, q -= 2)
|
|
*q = *(q + 1) = *p;
|
|
}
|
|
#ifndef FOREVER_16_BIT
|
|
}
|
|
else
|
|
{
|
|
for (register uint32 y = 0; y < starty; y++)
|
|
{
|
|
register uint8 *p = GFX.Screen + y * GFX.Pitch2 + 255;
|
|
register uint8 *q = GFX.Screen + y * GFX.Pitch2 + 510;
|
|
for (register int x = 255; x >= 0; x--, p--, q -= 2)
|
|
*q = *(q + 1) = *p;
|
|
}
|
|
}
|
|
#endif
|
|
IPPU.DoubleWidthPixels = TRUE;
|
|
IPPU.HalfWidthPixels = FALSE;
|
|
}
|
|
// BJ: And we have to change the height if Interlace gets set,
|
|
// too.
|
|
if (IPPU.Interlace && !IPPU.DoubleHeightPixels)
|
|
{
|
|
starty = GFX.StartY * 2;
|
|
endy = GFX.EndY * 2 + 1;
|
|
IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1;
|
|
IPPU.DoubleHeightPixels = TRUE;
|
|
GFX.Pitch2 = GFX.RealPitch;
|
|
GFX.Pitch = GFX.RealPitch * 2;
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.SixteenBit)
|
|
#endif
|
|
GFX.PPL = GFX.PPLx2 = GFX.RealPitch;
|
|
#ifndef FOREVER_16_BIT
|
|
else
|
|
GFX.PPL = GFX.PPLx2 = GFX.RealPitch << 1;
|
|
#endif
|
|
|
|
// The game has switched from non-interlaced to interlaced mode
|
|
// part way down the screen. Scale everything.
|
|
for (register int32 y = (int32) GFX.StartY - 1; y >= 0; y--)
|
|
{
|
|
memmove (GFX.Screen + y * 2 * GFX.Pitch2,
|
|
GFX.Screen + y * GFX.Pitch2,
|
|
GFX.Pitch2);
|
|
memmove (GFX.Screen + (y * 2 + 1) * GFX.Pitch2,
|
|
GFX.Screen + y * GFX.Pitch2,
|
|
GFX.Pitch2);
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32 black = BLACK | (BLACK << 16);
|
|
|
|
if (Settings.Transparency
|
|
#ifndef FOREVER_16_BIT
|
|
&& Settings.SixteenBit
|
|
#endif
|
|
)
|
|
{
|
|
if (GFX.Pseudo)
|
|
{
|
|
GFX.r2131 = 0x5f;
|
|
GFX.r212c &= (Memory.FillRAM [0x212d] | 0xf0);
|
|
GFX.r212d |= (Memory.FillRAM [0x212c] & 0x0f);
|
|
GFX.r2130 |= 2;
|
|
}
|
|
|
|
if (!PPU.ForcedBlanking && ADD_OR_SUB_ON_ANYTHING &&
|
|
(GFX.r2130 & 0x30) != 0x30 &&
|
|
!((GFX.r2130 & 0x30) == 0x10 && IPPU.Clip[1].Count[5] == 0))
|
|
{
|
|
struct ClipData *pClip;
|
|
|
|
GFX.FixedColour = BUILD_PIXEL (IPPU.XB [PPU.FixedColourRed],
|
|
IPPU.XB [PPU.FixedColourGreen],
|
|
IPPU.XB [PPU.FixedColourBlue]);
|
|
|
|
// Clear the z-buffer, marking areas 'covered' by the fixed
|
|
// colour as depth 1.
|
|
pClip = &IPPU.Clip [1];
|
|
|
|
// Clear the z-buffer
|
|
if (pClip->Count [5])
|
|
{
|
|
// Colour window enabled.
|
|
for (uint32 y = starty; y <= endy; y++)
|
|
{
|
|
ZeroMemory (GFX.SubZBuffer + y * GFX.ZPitch, IPPU.RenderedScreenWidth);
|
|
ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch, IPPU.RenderedScreenWidth);
|
|
|
|
if (IPPU.Clip [0].Count [5])
|
|
{
|
|
uint32 *p = (uint32 *) (GFX.SubScreen + y * GFX.Pitch2);
|
|
uint32 *q = (uint32 *) ((uint16 *) p + IPPU.RenderedScreenWidth);
|
|
while (p < q)
|
|
*p++ = black;
|
|
}
|
|
|
|
for (uint32 c = 0; c < pClip->Count [5]; c++)
|
|
{
|
|
if (pClip->Right [c][5] > pClip->Left [c][5])
|
|
{
|
|
memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
|
|
1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
|
|
|
|
if (IPPU.Clip [0].Count [5])
|
|
{
|
|
// Blast, have to clear the sub-screen to the fixed-colour
|
|
// because there is a colour window in effect clipping
|
|
// the main screen that will allow the sub-screen
|
|
// 'underneath' to show through.
|
|
|
|
uint16 *p = (uint16 *) (GFX.SubScreen + y * GFX.Pitch2);
|
|
uint16 *q = p + pClip->Right [c][5] * x2;
|
|
p += pClip->Left [c][5] * x2;
|
|
|
|
while (p < q)
|
|
*p++ = (uint16) GFX.FixedColour;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (uint32 y = starty; y <= endy; y++)
|
|
{
|
|
ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch, IPPU.RenderedScreenWidth);
|
|
memset (GFX.SubZBuffer + y * GFX.ZPitch, 1, IPPU.RenderedScreenWidth);
|
|
|
|
if (IPPU.Clip [0].Count [5])
|
|
{
|
|
// Blast, have to clear the sub-screen to the fixed-colour
|
|
// because there is a colour window in effect clipping
|
|
// the main screen that will allow the sub-screen
|
|
// 'underneath' to show through.
|
|
|
|
uint32 b = GFX.FixedColour | (GFX.FixedColour << 16);
|
|
uint32 *p = (uint32 *) (GFX.SubScreen + y * GFX.Pitch2);
|
|
uint32 *q = (uint32 *) ((uint16 *) p + IPPU.RenderedScreenWidth);
|
|
|
|
while (p < q)
|
|
*p++ = b;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ANYTHING_ON_SUB)
|
|
{
|
|
GFX.DB = GFX.SubZBuffer;
|
|
RenderScreen (GFX.SubScreen, TRUE, TRUE, SUB_SCREEN_DEPTH);
|
|
}
|
|
|
|
if (IPPU.Clip [0].Count [5])
|
|
{
|
|
for (uint32 y = starty; y <= endy; y++)
|
|
{
|
|
register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
|
|
register uint8 *d = GFX.SubZBuffer + y * GFX.ZPitch;
|
|
register uint8 *e = d + IPPU.RenderedScreenWidth;
|
|
|
|
while (d < e)
|
|
{
|
|
if (*d > 1)
|
|
*p = *(p + GFX.Delta);
|
|
else
|
|
*p = BLACK;
|
|
d++;
|
|
p++;
|
|
}
|
|
}
|
|
}
|
|
|
|
GFX.DB = GFX.ZBuffer;
|
|
RenderScreen (GFX.Screen, FALSE, FALSE, MAIN_SCREEN_DEPTH);
|
|
|
|
if (SUB_OR_ADD(5))
|
|
{
|
|
uint32 back = IPPU.ScreenColors [0];
|
|
uint32 Left = 0;
|
|
uint32 Right = 256;
|
|
uint32 Count;
|
|
|
|
pClip = &IPPU.Clip [0];
|
|
for (uint32 y = starty; y <= endy; y++)
|
|
{
|
|
if (!(Count = pClip->Count [5]))
|
|
{
|
|
Left = 0;
|
|
Right = 256 * x2;
|
|
Count = 1;
|
|
}
|
|
|
|
for (uint32 b = 0; b < Count; b++)
|
|
{
|
|
if (pClip->Count [5])
|
|
{
|
|
Left = pClip->Left [b][5] * x2;
|
|
Right = pClip->Right [b][5] * x2;
|
|
if (Right <= Left)
|
|
continue;
|
|
}
|
|
|
|
if (GFX.r2131 & 0x80)
|
|
{
|
|
if (GFX.r2131 & 0x40)
|
|
{
|
|
// Subtract, halving the result.
|
|
register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
|
|
register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
|
|
register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
|
|
register uint8 *e = d + Right;
|
|
uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
|
|
|
|
d += Left;
|
|
while (d < e)
|
|
{
|
|
if (*d == 0)
|
|
{
|
|
if (*s)
|
|
{
|
|
if (*s != 1)
|
|
*p = COLOR_SUB1_2 (back, *(p + GFX.Delta));
|
|
else
|
|
*p = back_fixed;
|
|
}
|
|
else
|
|
*p = (uint16) back;
|
|
}
|
|
d++;
|
|
p++;
|
|
s++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Subtract
|
|
register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
|
|
register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
|
|
register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
|
|
register uint8 *e = d + Right;
|
|
uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
|
|
|
|
d += Left;
|
|
while (d < e)
|
|
{
|
|
if (*d == 0)
|
|
{
|
|
if (*s)
|
|
{
|
|
if (*s != 1)
|
|
*p = COLOR_SUB (back, *(p + GFX.Delta));
|
|
else
|
|
*p = back_fixed;
|
|
}
|
|
else
|
|
*p = (uint16) back;
|
|
}
|
|
d++;
|
|
p++;
|
|
s++;
|
|
}
|
|
}
|
|
}
|
|
else if (GFX.r2131 & 0x40)
|
|
{
|
|
register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
|
|
register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
|
|
register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
|
|
register uint8 *e = d + Right;
|
|
uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
|
|
d += Left;
|
|
while (d < e)
|
|
{
|
|
if (*d == 0)
|
|
{
|
|
if (*s)
|
|
{
|
|
if (*s != 1)
|
|
*p = COLOR_ADD1_2 (back, *(p + GFX.Delta));
|
|
else
|
|
*p = back_fixed;
|
|
}
|
|
else
|
|
*p = (uint16) back;
|
|
}
|
|
d++;
|
|
p++;
|
|
s++;
|
|
}
|
|
}
|
|
else if (back != 0)
|
|
{
|
|
register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
|
|
register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
|
|
register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
|
|
register uint8 *e = d + Right;
|
|
uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
|
|
d += Left;
|
|
while (d < e)
|
|
{
|
|
if (*d == 0)
|
|
{
|
|
if (*s)
|
|
{
|
|
if (*s != 1)
|
|
*p = COLOR_ADD (back, *(p + GFX.Delta));
|
|
else
|
|
*p = back_fixed;
|
|
}
|
|
else
|
|
*p = (uint16) back;
|
|
}
|
|
d++;
|
|
p++;
|
|
s++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!pClip->Count [5])
|
|
{
|
|
// The backdrop has not been cleared yet - so
|
|
// copy the sub-screen to the main screen
|
|
// or fill it with the back-drop colour if the
|
|
// sub-screen is clear.
|
|
register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
|
|
register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
|
|
register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
|
|
register uint8 *e = d + Right;
|
|
d += Left;
|
|
while (d < e)
|
|
{
|
|
if (*d == 0)
|
|
{
|
|
if (*s)
|
|
{
|
|
if (*s != 1)
|
|
*p = *(p + GFX.Delta);
|
|
else
|
|
*p = GFX.FixedColour;
|
|
}
|
|
else
|
|
*p = (uint16) back;
|
|
}
|
|
d++;
|
|
p++;
|
|
s++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // --if (SUB_OR_ADD(5))
|
|
else
|
|
{
|
|
// Subscreen not being added to back
|
|
uint32 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
|
|
pClip = &IPPU.Clip [0];
|
|
|
|
if (pClip->Count [5])
|
|
{
|
|
for (uint32 y = starty; y <= endy; y++)
|
|
{
|
|
for (uint32 b = 0; b < pClip->Count [5]; b++)
|
|
{
|
|
uint32 Left = pClip->Left [b][5] * x2;
|
|
uint32 Right = pClip->Right [b][5] * x2;
|
|
uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
|
|
uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
|
|
uint8 *e = d + Right;
|
|
d += Left;
|
|
|
|
while (d < e)
|
|
{
|
|
if (*d == 0)
|
|
*p = (int16) back;
|
|
d++;
|
|
p++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (uint32 y = starty; y <= endy; y++)
|
|
{
|
|
uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
|
|
uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
|
|
uint8 *e = d + 256 * x2;
|
|
|
|
while (d < e)
|
|
{
|
|
if (*d == 0)
|
|
*p = (int16) back;
|
|
d++;
|
|
p++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} //force blanking
|
|
else
|
|
{
|
|
// 16bit and transparency but currently no transparency effects in
|
|
// operation.
|
|
|
|
uint32 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
|
|
|
|
if (PPU.ForcedBlanking)
|
|
back = black;
|
|
|
|
if (IPPU.Clip [0].Count[5])
|
|
{
|
|
for (uint32 y = starty; y <= endy; y++)
|
|
{
|
|
uint32 *p = (uint32 *) (GFX.Screen + y * GFX.Pitch2);
|
|
uint32 *q = (uint32 *) ((uint16 *) p + IPPU.RenderedScreenWidth);
|
|
|
|
while (p < q)
|
|
*p++ = black;
|
|
|
|
for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
|
|
{
|
|
if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
|
|
{
|
|
uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
|
|
uint16 *q = p + IPPU.Clip [0].Right [c][5] * x2;
|
|
p += IPPU.Clip [0].Left [c][5] * x2;
|
|
|
|
while (p < q)
|
|
*p++ = (uint16) back;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (uint32 y = starty; y <= endy; y++)
|
|
{
|
|
uint32 *p = (uint32 *) (GFX.Screen + y * GFX.Pitch2);
|
|
uint32 *q = (uint32 *) ((uint16 *) p + IPPU.RenderedScreenWidth);
|
|
while (p < q)
|
|
*p++ = back;
|
|
}
|
|
}
|
|
|
|
if (!PPU.ForcedBlanking)
|
|
{
|
|
for (uint32 y = starty; y <= endy; y++)
|
|
{
|
|
ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch, IPPU.RenderedScreenWidth);
|
|
}
|
|
GFX.DB = GFX.ZBuffer;
|
|
RenderScreen (GFX.Screen, FALSE, TRUE, SUB_SCREEN_DEPTH);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
}
|
|
|
|
if (Settings.SupportHiRes)
|
|
{
|
|
if (PPU.BGMode != 5 && PPU.BGMode != 6 && IPPU.DoubleWidthPixels)
|
|
{
|
|
// Mixure of background modes used on screen - scale width
|
|
// of all non-mode 5 and 6 pixels.
|
|
#ifndef FOREVER_16_BIT
|
|
if (Settings.SixteenBit)
|
|
{
|
|
#endif
|
|
for (register uint32 y = starty; y <= endy; y++)
|
|
{
|
|
register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + 255;
|
|
register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + 510;
|
|
for (register int x = 255; x >= 0; x--, p--, q -= 2)
|
|
*q = *(q + 1) = *p;
|
|
}
|
|
#ifndef FOREVER_16_BIT
|
|
}
|
|
else
|
|
{
|
|
for (register uint32 y = starty; y <= endy; y++)
|
|
{
|
|
register uint8 *p = GFX.Screen + y * GFX.Pitch2 + 255;
|
|
register uint8 *q = GFX.Screen + y * GFX.Pitch2 + 510;
|
|
for (register int x = 255; x >= 0; x--, p--, q -= 2)
|
|
*q = *(q + 1) = *p;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Double the height of the pixels just drawn
|
|
FIX_INTERLACE(GFX.Screen, FALSE, GFX.ZBuffer);
|
|
}
|
|
|
|
IPPU.PreviousLine = IPPU.CurrentLine;
|
|
}
|
|
|
|
|