/*
* Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
*
* (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
*                           Jerremy Koot (jkoot@snes9x.com)
*
* Super FX C emulator code
* (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
*                           Gary Henderson.
* Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
*
* DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
* C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
* C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
*
* DOS port code 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"

#define M7 19
#define M8 19

void ComputeClipWindows ();

extern int os9x_BG0,os9x_BG1,os9x_BG2,os9x_BG3,os9x_OBJ,os9x_easy;

extern void S9xSetupOBJ(void);

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 ON_MAIN(N) \
(GFX.r212c & (1 << (N)) && \
!(PPUPack.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)) && \
!(PPUPack.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 BLACK BUILD_PIXEL(0,0,0)

void orgDrawTileHi16 (uint32 Tile, uint32 Offset, uint32 StartLine,
	         uint32 LineCount);
void orgDrawClippedTileHi16 (uint32 Tile, uint32 Offset,
		        uint32 StartPixel, uint32 Width,
		        uint32 StartLine, uint32 LineCount);

void orgDrawTile16 (uint32 Tile, uint32 Offset, uint32 StartLine,
	         uint32 LineCount);
void orgDrawClippedTile16 (uint32 Tile, uint32 Offset,
		        uint32 StartPixel, uint32 Width,
		        uint32 StartLine, uint32 LineCount);
void orgDrawTile16x2 (uint32 Tile, uint32 Offset, uint32 StartLine,
		   uint32 LineCount);
void orgDrawClippedTile16x2 (uint32 Tile, uint32 Offset,
			  uint32 StartPixel, uint32 Width,
			  uint32 StartLine, uint32 LineCount);
void orgDrawTile16x2x2 (uint32 Tile, uint32 Offset, uint32 StartLine,
		     uint32 LineCount);
void orgDrawClippedTile16x2x2 (uint32 Tile, uint32 Offset,
			    uint32 StartPixel, uint32 Width,
			    uint32 StartLine, uint32 LineCount);
void orgDrawLargePixel16 (uint32 Tile, uint32 Offset,
		       uint32 StartPixel, uint32 Pixels,
		       uint32 StartLine, uint32 LineCount);

void orgDrawTile16Add (uint32 Tile, uint32 Offset, uint32 StartLine,
		    uint32 LineCount);

void orgDrawClippedTile16Add (uint32 Tile, uint32 Offset,
			   uint32 StartPixel, uint32 Width,
			   uint32 StartLine, uint32 LineCount);

void orgDrawTile16Add1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
		       uint32 LineCount);

void orgDrawClippedTile16Add1_2 (uint32 Tile, uint32 Offset,
			      uint32 StartPixel, uint32 Width,
			      uint32 StartLine, uint32 LineCount);

void orgDrawTile16FixedAdd1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
			    uint32 LineCount);

void orgDrawClippedTile16FixedAdd1_2 (uint32 Tile, uint32 Offset,
				   uint32 StartPixel, uint32 Width,
				   uint32 StartLine, uint32 LineCount);

void orgDrawTile16Sub (uint32 Tile, uint32 Offset, uint32 StartLine,
		    uint32 LineCount);

void orgDrawClippedTile16Sub (uint32 Tile, uint32 Offset,
			   uint32 StartPixel, uint32 Width,
			   uint32 StartLine, uint32 LineCount);

void orgDrawTile16Sub1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
		       uint32 LineCount);

void orgDrawClippedTile16Sub1_2 (uint32 Tile, uint32 Offset,
			      uint32 StartPixel, uint32 Width,
			      uint32 StartLine, uint32 LineCount);

void orgDrawTile16FixedSub1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
			    uint32 LineCount);

void orgDrawClippedTile16FixedSub1_2 (uint32 Tile, uint32 Offset,
				   uint32 StartPixel, uint32 Width,
				   uint32 StartLine, uint32 LineCount);

void orgDrawLargePixel16Add (uint32 Tile, uint32 Offset,
			  uint32 StartPixel, uint32 Pixels,
			  uint32 StartLine, uint32 LineCount);

void orgDrawLargePixel16Add1_2 (uint32 Tile, uint32 Offset,
			     uint32 StartPixel, uint32 Pixels,
			     uint32 StartLine, uint32 LineCount);

void orgDrawLargePixel16Sub (uint32 Tile, uint32 Offset,
			  uint32 StartPixel, uint32 Pixels,
			  uint32 StartLine, uint32 LineCount);

void orgDrawLargePixel16Sub1_2 (uint32 Tile, uint32 Offset,
			     uint32 StartPixel, uint32 Pixels,
			     uint32 StartLine, uint32 LineCount);



inline void orgSelectTileRenderer (bool8 normal)
{
	DrawHiResTilePtr= orgDrawTileHi16;
	DrawHiResClippedTilePtr = orgDrawClippedTileHi16;


    if (normal)
    {

	DrawTilePtr = orgDrawTile16;
	DrawClippedTilePtr = orgDrawClippedTile16;
	DrawLargePixelPtr = orgDrawLargePixel16;
    }
    else
    {

	if (GFX.r2131 & 0x80)
	{
	    if (GFX.r2131 & 0x40)
	    {
		if (GFX.r2130 & 2)
		{

		    DrawTilePtr = orgDrawTile16Sub1_2;
		    DrawClippedTilePtr = orgDrawClippedTile16Sub1_2;
		}
		else
		{

		    // Fixed colour substraction
		    DrawTilePtr = orgDrawTile16FixedSub1_2;
		    DrawClippedTilePtr = orgDrawClippedTile16FixedSub1_2;
		}
		DrawLargePixelPtr = orgDrawLargePixel16Sub1_2;
	    }
	    else
	    {

		DrawTilePtr = orgDrawTile16Sub;
		DrawClippedTilePtr = orgDrawClippedTile16Sub;
		DrawLargePixelPtr = orgDrawLargePixel16Sub;
	    }
	}
	else
	{
	    if (GFX.r2131 & 0x40)
	    {
		if (GFX.r2130 & 2)
		{

		    DrawTilePtr = orgDrawTile16Add1_2;
		    DrawClippedTilePtr = orgDrawClippedTile16Add1_2;
		}
		else
		{

		    // Fixed colour addition
		    DrawTilePtr = orgDrawTile16FixedAdd1_2;
		    DrawClippedTilePtr = orgDrawClippedTile16FixedAdd1_2;
		}
		DrawLargePixelPtr = orgDrawLargePixel16Add1_2;
	    }
	    else
	    {

		DrawTilePtr = orgDrawTile16Add;
		DrawClippedTilePtr = orgDrawClippedTile16Add;
		DrawLargePixelPtr = orgDrawLargePixel16Add;
	    }
	}
    }
}

void orgDrawOBJS (bool8 OnMain = FALSE, uint8 D = 0)
{
    uint32 O;
    uint32 BaseTile, Tile;

    CHECK_SOUND();

    BG.BitShift = 4;
    BG.TileShift = 5;
    BG.TileAddress = PPUPack.PPU.OBJNameBase;
    BG.StartPalette = 128;
    BG.PaletteShift = 4;
    BG.PaletteMask = 7;
    BG.Buffer = PPUPack.IPPU.TileCache [TILE_4BIT];
    BG.Buffered = PPUPack.IPPU.TileCached [TILE_4BIT];
    BG.NameSelect = PPUPack.PPU.OBJNameSelect;
    BG.DirectColourMode = FALSE;

//    GFX.PixSize = 1;



	DrawTilePtr = orgDrawTile16;
	DrawClippedTilePtr = orgDrawClippedTile16;

    GFX.Z1 = D + 2;

    int I = 0;
    for (int S = GFX.OBJList [I++]; S >= 0; S = GFX.OBJList [I++])
    {
	int VPos = GFX.VPositions [S];
	int Size = GFX.Sizes[S];
	int TileInc = 1;
	int Offset;

	if (VPos + Size <= (int) GFX.StartY || VPos > (int) GFX.EndY)
	    continue;

	if (OnMain && SUB_OR_ADD(4))
	{
	    orgSelectTileRenderer (!GFX.Pseudo && PPUPack.PPU.OBJ [S].Palette < 4);
	}

	BaseTile = PPUPack.PPU.OBJ[S].Name | (PPUPack.PPU.OBJ[S].Palette << 10);

	if (PPUPack.PPU.OBJ[S].HFlip)
	{
	    BaseTile += ((Size >> 3) - 1) | H_FLIP;
	    TileInc = -1;
	}
	if (PPUPack.PPU.OBJ[S].VFlip)
	    BaseTile |= V_FLIP;

	int clipcount = GFX.pCurrentClip->Count [4];
	if (!clipcount)
	    clipcount = 1;

	GFX.Z2 = (PPUPack.PPU.OBJ[S].Priority + 1) * 4 + D;

	for (int clip = 0; clip < clipcount; clip++)
	{
	    int Left;
	    int Right;
	    if (!GFX.pCurrentClip->Count [4])
	    {
		Left = 0;
		Right = 256;
	    }
	    else
	    {
		Left = GFX.pCurrentClip->Left [clip][4];
		Right = GFX.pCurrentClip->Right [clip][4];
	    }

	    if (Right <= Left || PPUPack.PPU.OBJ[S].HPos + Size <= Left ||
		PPUPack.PPU.OBJ[S].HPos >= Right)
		continue;

	    for (int Y = 0; Y < Size; Y += 8)
	    {
		if (VPos + Y + 7 >= (int) GFX.StartY && VPos + Y <= (int) GFX.EndY)
		{
		    int StartLine;
		    int TileLine;
		    int LineCount;
		    int Last;

		    if ((StartLine = VPos + Y) < (int) GFX.StartY)
		    {
			StartLine = GFX.StartY - StartLine;
			LineCount = 8 - StartLine;
		    }
		    else
		    {
			StartLine = 0;
			LineCount = 8;
		    }
		    if ((Last = VPos + Y + 7 - GFX.EndY) > 0)
			if ((LineCount -= Last) <= 0)
			    break;

		    TileLine = StartLine << 3;
		    O = (VPos + Y + StartLine) * GFX.PPL;
		    if (!PPUPack.PPU.OBJ[S].VFlip)
			Tile = BaseTile + (Y << 1);
		    else
			Tile = BaseTile + ((Size - Y - 8) << 1);

		    int Middle = Size >> 3;
		    if (PPUPack.PPU.OBJ[S].HPos < Left)
		    {
			Tile += ((Left - PPUPack.PPU.OBJ[S].HPos) >> 3) * TileInc;
			Middle -= (Left - PPUPack.PPU.OBJ[S].HPos) >> 3;
			O += Left/* * GFX.PixSize*/;
			if ((Offset = (Left - PPUPack.PPU.OBJ[S].HPos) & 7))
			{
			    O -= Offset/* * GFX.PixSize*/;
			    int W = 8 - Offset;
			    int Width = Right - Left;
			    if (W > Width)
				W = Width;
			    (*DrawClippedTilePtr) (Tile, O, Offset, W,
						   TileLine, LineCount);

			    if (W >= Width)
				continue;
			    Tile += TileInc;
			    Middle--;
			    O += 8/* * GFX.PixSize*/;
			}
		    }
		    else
			O += PPUPack.PPU.OBJ[S].HPos/* * GFX.PixSize*/;

		    if (PPUPack.PPU.OBJ[S].HPos + Size >= Right)
		    {
			Middle -= ((PPUPack.PPU.OBJ[S].HPos + Size + 7) -
				   Right) >> 3;
			Offset = (Right - (PPUPack.PPU.OBJ[S].HPos + Size)) & 7;
		    }
		    else
			Offset = 0;

		    for (int X = 0; X < Middle; X++, O += 8/* * GFX.PixSize*/,
			 Tile += TileInc)
		    {
			(*DrawTilePtr) (Tile, O, TileLine, LineCount);
		    }
		    if (Offset)
		    {
			(*DrawClippedTilePtr) (Tile, O, 0, Offset,
					       TileLine, LineCount);
		    }
		}
	    }
	}
    }
}

void orgDrawBackgroundMosaic (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 *) &VRAM[PPUPack.PPU.BG[bg].SCBase << 1];

    if (PPUPack.PPU.BG[bg].SCSize & 1)
	SC1 = SC0 + 1024;
    else
	SC1 = SC0;

	if((SC1-(unsigned short*)VRAM)>0x10000)
		SC1-=0x10000;


    if (PPUPack.PPU.BG[bg].SCSize & 2)
	SC2 = SC1 + 1024;
    else
	SC2 = SC0;

	if((SC2-(unsigned short*)VRAM)>0x10000)
		SC2-=0x10000;


    if (PPUPack.PPU.BG[bg].SCSize & 1)
	SC3 = SC2 + 1024;
    else
	SC3 = SC2;

	if((SC3-(unsigned short*)VRAM)>0x10000)
		SC3-=0x10000;

    uint32 Lines;
    uint32 OffsetMask;
    uint32 OffsetShift;

    if (BG.TileSizeIs16)
    {
	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;
	uint32 MosaicOffset = Y % PPUPack.PPU.Mosaic;

	for (Lines = 1; Lines < PPUPack.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;

	uint32 ClipCount = GFX.pCurrentClip->Count [bg];
	uint32 HPos = HOffset;
	uint32 PixWidth = PPUPack.PPU.Mosaic;

	if (!ClipCount)
	    ClipCount = 1;

	for (uint32 clip = 0; clip < ClipCount; clip++)
	{
	    if (GFX.pCurrentClip->Count [bg])
	    {
		Left = GFX.pCurrentClip->Left [clip][bg];
		Right = GFX.pCurrentClip->Right [clip][bg];
		uint32 r = Left % PPUPack.PPU.Mosaic;
		HPos = HOffset + Left;
		PixWidth = PPUPack.PPU.Mosaic - r;
	    }
	    uint32 s = Y * GFX.PPL + Left/* * GFX.PixSize*/;
	    for (uint32 x = Left; x < Right; x += PixWidth,
		 s += PixWidth/* * GFX.PixSize*/,
		 HPos += PixWidth, PixWidth = PPUPack.PPU.Mosaic)
	    {
		uint32 Quot = (HPos & OffsetMask) >> 3;

		if (x + PixWidth >= Right)
		    PixWidth = Right - x;

		if (!BG.TileSizeIs16)
		{
		    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];

		// orgDraw tile...
		if (BG.TileSizeIs16)
		{
		    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, s, HPos & 7, PixWidth,
					  VirtAlign, Lines);
	    }
	}
    }
}

void orgDrawBackgroundOffset (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 *) &VRAM[PPUPack.PPU.BG[2].SCBase << 1];

    if (PPUPack.PPU.BG[2].SCSize & 1)
	BPS1 = BPS0 + 1024;
    else
	BPS1 = BPS0;

    if (PPUPack.PPU.BG[2].SCSize & 2)
	BPS2 = BPS1 + 1024;
    else
	BPS2 = BPS0;

    if (PPUPack.PPU.BG[2].SCSize & 1)
	BPS3 = BPS2 + 1024;
    else
	BPS3 = BPS2;

    SC0 = (uint16 *) &VRAM[PPUPack.PPU.BG[bg].SCBase << 1];

    if (PPUPack.PPU.BG[bg].SCSize & 1)
	SC1 = SC0 + 1024;
    else
	SC1 = SC0;

	if((SC1-(unsigned short*)VRAM)>0x10000)
		SC1-=0x10000;


    if (PPUPack.PPU.BG[bg].SCSize & 2)
	SC2 = SC1 + 1024;
    else
	SC2 = SC0;

	if((SC2-(unsigned short*)VRAM)>0x10000)
		SC2-=0x10000;


    if (PPUPack.PPU.BG[bg].SCSize & 1)
	SC3 = SC2 + 1024;
    else
	SC3 = SC2;

	if((SC3-(unsigned short*)VRAM)>0x10000)
		SC3-=0x10000;


    static const int Lines = 1;
    int OffsetMask;
    int OffsetShift;
    int OffsetEnableMask = 1 << (bg + 13);

    if (BG.TileSizeIs16)
    {
	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.TileSizeIs16)
		{
		    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 -= Offset/* * GFX.PixSize*/;
		Tile = READ_2BYTES(t);
		GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];

		if (!BG.TileSizeIs16)
		    (*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 += (Offset + Count)/* * GFX.PixSize*/;
		MaxCount = 8;
	    }
	}
    }
}

void orgDrawBackgroundMode5 (uint32 /* BGMODE */, uint32 bg, uint8 Z1, uint8 
Z2)
{
    CHECK_SOUND();

    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 *) &VRAM[PPUPack.PPU.BG[bg].SCBase << 1];

    if ((PPUPack.PPU.BG[bg].SCSize & 1))
	SC1 = SC0 + 1024;
    else
	SC1 = SC0;

	if((SC1-(unsigned short*)VRAM)>0x10000)
		SC1=(uint16*)&VRAM[(((uint8*)SC1)-VRAM)%0x10000];

    if ((PPUPack.PPU.BG[bg].SCSize & 2))
	SC2 = SC1 + 1024;
    else
	SC2 = SC0;

		if((SC2-(unsigned short*)VRAM)>0x10000)
		SC2=(uint16*)&VRAM[(((uint8*)SC2)-VRAM)%0x10000];


    if ((PPUPack.PPU.BG[bg].SCSize & 1))
	SC3 = SC2 + 1024;
    else
	SC3 = SC2;

	if((SC3-(unsigned short*)VRAM)>0x10000)
		SC3=(uint16*)&VRAM[(((uint8*)SC3)-VRAM)%0x10000];


    int Lines;
    int VOffsetMask;
    int VOffsetShift;

    if (BG.TileSizeIs16)
    {
	VOffsetMask = 0x3ff;
	VOffsetShift = 4;
    }
    else
    {
	VOffsetMask = 0x1ff;
	VOffsetShift = 3;
    }
    int endy = GFX.EndY;

    for (int Y = GFX.StartY; Y <= endy; Y += Lines)
    {
	int y = 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 = (Left>>1) /** GFX.PixSize*/ + Y * 256;//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 -= Offset>>1;
		Tile = READ_2BYTES (t);
		GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];

		if (!BG.TileSizeIs16)
		{
		    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 += /*8*/4;
	    }

	    // Middle, unclipped tiles
	    Count = Width - Count;
	    int Middle = Count >> 3;
	    Count &= 7;
	    for (int C = Middle; C > 0; s += /*8*/4, Quot++, C--)
	    {
		Tile = READ_2BYTES(t);
		GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
		if (!BG.TileSizeIs16)
		{
		    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.TileSizeIs16)
		{
		    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 = GFX.RealPitch;
    GFX.PPL = GFX.PPLx2 >> 1;
}

void orgDrawBackground (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
{
//    GFX.PixSize = 1;

    BG.TileSizeIs16 = PPUPack.PPU.BG[bg].BGSize;
    BG.BitShift = BitShifts[BGMode][bg];
    BG.TileShift = TileShifts[BGMode][bg];
    BG.TileAddress = PPUPack.PPU.BG[bg].NameBase << 1;
    BG.NameSelect = 0;
    BG.Buffer = PPUPack.IPPU.TileCache [Depths [BGMode][bg]];
    BG.Buffered = PPUPack.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 (PPUPack.PPU.BGMosaic [bg] && PPUPack.PPU.Mosaic > 1)
    {
	orgDrawBackgroundMosaic (BGMode, bg, Z1, Z2);
	return;

    }
    switch (BGMode)
    {
    case 2:
	if (Settings.WrestlemaniaArcade)
	    break;
    case 4: // Used by Puzzle Bobble
       orgDrawBackgroundOffset (BGMode, bg, Z1, Z2);
	return;

    case 5:
    case 6: // XXX: is also offset per tile.
//	if (Settings.SupportHiRes)
	{
	    orgDrawBackgroundMode5 (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 *) &VRAM[PPUPack.PPU.BG[bg].SCBase << 1];

    if (PPUPack.PPU.BG[bg].SCSize & 1)	SC1 = SC0 + 1024;
    else	SC1 = SC0;

	if(SC1>=(unsigned 
short*)(VRAM+0x10000))		SC1=(uint16*)&VRAM[((uint8*)SC1-&VRAM[0])%0x10000];

    if (PPUPack.PPU.BG[bg].SCSize & 2)	SC2 = SC1 + 1024;
    else	SC2 = SC0;

		if((SC2-(unsigned short*)VRAM)>0x10000)		SC2-=0x10000;


    if (PPUPack.PPU.BG[bg].SCSize & 1)	SC3 = SC2 + 1024;
    else	SC3 = SC2;

	if((SC3-(unsigned short*)VRAM)>0x10000)		SC3-=0x10000;


    int Lines;
    int OffsetMask;
    int OffsetShift;

    if (BG.TileSizeIs16)
    {
	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.TileSizeIs16)
	    {
		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.TileSizeIs16)
		{
		    (*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.TileSizeIs16)
		{
		    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 += 8/* * GFX.PixSize*/;
	    }

	    // Middle, unclipped tiles
	    Count = Width - Count;
	    int Middle = Count >> 3;
	    Count &= 7;
	    for (int C = Middle; C > 0; s += 8/* * GFX.PixSize*/, Quot++, C--)
	    {
		Tile = READ_2BYTES(t);
		GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];

		if (BG.TileSizeIs16)
		{
		    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.TileSizeIs16)
		{
		    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.TileSizeIs16)
		    (*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) \
    CHECK_SOUND(); \
\
    uint8 *VRAM1 = VRAM + 1; \
    if (GFX.r2130 & 1) \
    { \
	if (PPUPack.IPPU.DirectColourMapsNeedRebuild) \
	    S9xBuildDirectColourMaps (); \
	GFX.ScreenColors = DirectColourMaps [0]; \
    } \
    else \
	GFX.ScreenColors = PPUPack.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 (PPUPack.PPU.Mode7VFlip) \
	    yy = 261 - (int) Line; \
	else \
	    yy = Line; \
\
	if (PPUPack.PPU.Mode7Repeat == 0) \
	    yy += (VOffset - CentreY) % 1023; \
	else \
	    yy += 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 (PPUPack.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; \
	    if (PPUPack.PPU.Mode7Repeat == 0) \
		xx = startx + (HOffset - CentreX) % 1023; \
	    else \
		xx = startx + HOffset - CentreX; \
	    int AA = l->MatrixA * xx; \
	    int CC = l->MatrixC * xx; \
		AA += BB;\
		CC += DD;\
		\
	    if (!PPUPack.PPU.Mode7Repeat) \
	    { \
	    	if (cc == 0) {\
				register uint8* AdrY;\
				register int AdrY2;\
				int Y = CC>>4; AdrY = &VRAM[((Y & 0x3f80) << 1)]; AdrY2 = (Y & 0x70);\
\
				for (int x = startx; x != endx; x += dir, AA += aa, p++, d++) \
				{ \
				    int X = (AA >> 7); \
				    uint8 *TileData = VRAM1 + (AdrY[(X >> 3) & 0xfe] << 7); \
				    uint32 b = *(TileData + AdrY2 + (X & 14)); \
				    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 >> 7;\
				  	int Y = CC >> 4;\
			  		uint8* TileData = VRAM1 + (VRAM[((Y & 0x3f80) << 1) + ((X >> 3) & 0xfe)] << 7); \
					uint32 b = *(TileData + (Y & 0x70) + (X & 14)); \
				    GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
				    if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
				    { \
						*p = (FUNC); \
						*d = GFX.Z1; \
				    } \
				} \
        	}\
	    } \
	    else \
	    { \
			if (Settings.Dezaemon && PPUPack.PPU.Mode7Repeat == 2) \
				for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
				{ \
				    int X = (AA >> 8) & 0x7ff; \
				    int Y = (CC >> 8) & 0x7ff; \
		\
				    if (((X | Y) & ~0x3ff) == 0) \
				    { \
					uint8 *TileData = VRAM1 + (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 (PPUPack.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; \
						    } \
						} \
				    } \
				} \
			else\
				for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
				{ \
				    int X = (AA >> 8); \
				    int Y = (CC >> 8); \
		\
				    if (((X | Y) & ~0x3ff) == 0) \
				    { \
					uint8 *TileData = VRAM1 + (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 (PPUPack.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; \
						    } \
						} \
				    } \
				} \
	    } \
	} \
    }

void orgDrawBGMode7Background16 (uint8 *Screen, int bg)
{
    RENDER_BACKGROUND_MODE7 (uint16, GFX.ScreenColors [b & GFX.Mode7Mask]);
}

void orgDrawBGMode7Background16Add (uint8 *Screen, int bg)
{
    RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
					(*(d + GFX.DepthDelta) != 1 ?
					    COLOR_ADD (GFX.ScreenColors [b & GFX.Mode7Mask],
						       p [GFX.Delta]) :
					    COLOR_ADD (GFX.ScreenColors [b & GFX.Mode7Mask],
						       GFX.FixedColour)) :
					 GFX.ScreenColors [b & GFX.Mode7Mask]);
}

void orgDrawBGMode7Background16Add1_2 (uint8 *Screen, int bg)
{
    RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
					(*(d + GFX.DepthDelta) != 1 ?
					    COLOR_ADD1_2 (GFX.ScreenColors [b & GFX.Mode7Mask],
						       p [GFX.Delta]) :
					    COLOR_ADD (GFX.ScreenColors [b & GFX.Mode7Mask],
						       GFX.FixedColour)) :
					 GFX.ScreenColors [b & GFX.Mode7Mask]);
}

void orgDrawBGMode7Background16Sub (uint8 *Screen, int bg)
{
    RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
					(*(d + GFX.DepthDelta) != 1 ?
					    COLOR_SUB (GFX.ScreenColors [b & GFX.Mode7Mask],
						       p [GFX.Delta]) :
					    COLOR_SUB (GFX.ScreenColors [b & GFX.Mode7Mask],
						       GFX.FixedColour)) :
					 GFX.ScreenColors [b & GFX.Mode7Mask]);
}

void orgDrawBGMode7Background16Sub1_2 (uint8 *Screen, int bg)
{
    RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
					(*(d + GFX.DepthDelta) != 1 ?
					    COLOR_SUB1_2 (GFX.ScreenColors [b & GFX.Mode7Mask],
						       p [GFX.Delta]) :
					    COLOR_SUB (GFX.ScreenColors [b & GFX.Mode7Mask],
						       GFX.FixedColour)) :
					 GFX.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);

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 = &PPUPack.IPPU.Clip [0];
	BG0 = ON_MAIN (0) &&  os9x_BG0;
	BG1 = ON_MAIN (1) &&  os9x_BG1;
	BG2 = ON_MAIN (2) &&  os9x_BG2;
	BG3 = ON_MAIN (3) &&  os9x_BG3;
	OB  = ON_MAIN (4) &&  os9x_OBJ;
    }
    else
    {
	GFX.pCurrentClip = &PPUPack.IPPU.Clip [1];
	BG0 = ON_SUB (0) &&  os9x_BG0;
	BG1 = ON_SUB (1) &&  os9x_BG1;
	BG2 = ON_SUB (2) &&  os9x_BG2;
	BG3 = ON_SUB (3) &&  os9x_BG3;
	OB  = ON_SUB (4) &&  os9x_OBJ;
    }

    sub |= force_no_add;

    if (PPUPack.PPU.BGMode <= 1)
    {

	if (OB)
	{
	    orgSelectTileRenderer (sub || !SUB_OR_ADD(4));
	    orgDrawOBJS (!sub, D);
	}
	if (BG0)
	{

	    orgSelectTileRenderer (sub || !SUB_OR_ADD(0));
	    orgDrawBackground (PPUPack.PPU.BGMode, 0, D + 10, D + 14);
	}
	if (BG1)
	{
	    orgSelectTileRenderer (sub || !SUB_OR_ADD(1));
	    orgDrawBackground (PPUPack.PPU.BGMode, 1, D + 9, D + 13);
	}
	if (BG2)
	{
	    orgSelectTileRenderer (sub || !SUB_OR_ADD(2));
	    orgDrawBackground (PPUPack.PPU.BGMode, 2, D + 3, (FillRAM [0x2105] & 8) == 0 ? 
D + 6 : D + 17);
	}
	if (BG3 && PPUPack.PPU.BGMode == 0)
	{
	    orgSelectTileRenderer (sub || !SUB_OR_ADD(3));
	    orgDrawBackground (PPUPack.PPU.BGMode, 3, D + 2, D + 5);
	}
    }
    else if (PPUPack.PPU.BGMode != 7)
    {

	if (OB)
	{
	    orgSelectTileRenderer (sub || !SUB_OR_ADD(4));
	    orgDrawOBJS (!sub, D);
	}
	if (BG0)
	{

	    orgSelectTileRenderer (sub || !SUB_OR_ADD(0));
	    orgDrawBackground (PPUPack.PPU.BGMode, 0, D + 5, D + 13);
	}
	if (PPUPack.PPU.BGMode != 6 && BG1)
	{
	    orgSelectTileRenderer (sub || !SUB_OR_ADD(1));
	    orgDrawBackground (PPUPack.PPU.BGMode, 1, D + 2, D + 9);
	}
    }
    else
    {

	if (OB)
	{
	    orgSelectTileRenderer (sub || !SUB_OR_ADD(4));
	    orgDrawOBJS (!sub, D);
	}
	if (BG0 || ((FillRAM [0x2133] & 0x40) && BG1))
	{
	    int bg;

	    if (FillRAM [0x2133] & 0x40)
	    {
		GFX.Mode7Mask = 0x7f;
		GFX.Mode7PriorityMask = 0x80;
		Mode7Depths [0] = 5 + 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))
	    {

		    orgDrawBGMode7Background16 (Screen, bg);
	    }
	    else
	    {
		if (GFX.r2131 & 0x80)
		{
		    if (GFX.r2131 & 0x40)
		    {
			    orgDrawBGMode7Background16Sub1_2 (Screen, bg);
		    }
		    else
		    {
			    orgDrawBGMode7Background16Sub (Screen, bg);
		    }
		}
		else
		{
		    if (GFX.r2131 & 0x40)
		    {
			    orgDrawBGMode7Background16Add1_2 (Screen, bg);
		    }
		    else
		    {

			    orgDrawBGMode7Background16Add (Screen, bg);
		    }
		}
	    }
	}
    }
}


void orgS9xUpdateScreen ()
{
  int32 x2 = 1;

  /*GFX.S = GFX.Screen;
  GFX.r2131 = FillRAM [0x2131];
  GFX.r212c = FillRAM [0x212c];
  GFX.r212d = FillRAM [0x212d];
  GFX.r2130 = FillRAM [0x2130];
  GFX.Pseudo = (FillRAM [0x2133] & 8) != 0 &&
    (GFX.r212c & 15) != (GFX.r212d & 15) &&
    (GFX.r2131 & 0x3f) == 0;

  if (PPUPack.IPPU.OBJChanged)
    S9xSetupOBJ ();

  if (PPUPack.PPU.RecomputeClipWindows)
    {
      ComputeClipWindows ();
      PPUPack.PPU.RecomputeClipWindows = FALSE;
    }

  GFX.StartY = PPUPack.IPPU.PreviousLine;
  if ((GFX.EndY = PPUPack.IPPU.CurrentLine - 1) >= PPUPack.PPU.ScreenHeight)
    GFX.EndY = PPUPack.PPU.ScreenHeight - 1;
*/
  uint32 starty = GFX.StartY;
  uint32 endy = GFX.EndY;

  uint32 black = BLACK | (BLACK << 16);



      if (GFX.Pseudo)
	{
	  GFX.r2131 = 0x5f;
	  GFX.r212d = (FillRAM [0x212c] ^
		       FillRAM [0x212d]) & 15;
	  GFX.r212c &= ~GFX.r212d;
	  GFX.r2130 |= 2;
	}

      if (!os9x_easy && !PPUPack.PPU.ForcedBlanking && ADD_OR_SUB_ON_ANYTHING &&
	  (GFX.r2130 & 0x30) != 0x30 &&
	  !((GFX.r2130 & 0x30) == 0x10 && PPUPack.IPPU.Clip[1].Count[5] == 0))
	{

	  struct ClipData *pClip;

	  GFX.FixedColour = BUILD_PIXEL (PPUPack.IPPU.XB [PPUPack.PPU.FixedColourRed],
					 PPUPack.IPPU.XB [PPUPack.PPU.FixedColourGreen],
					 PPUPack.IPPU.XB [PPUPack.PPU.FixedColourBlue]);

	  // Clear the z-buffer, marking areas 'covered' by the fixed
	  // colour as depth 1.
	  pClip = &PPUPack.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,
			      PPUPack.IPPU.RenderedScreenWidth);
		  ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
			      PPUPack.IPPU.RenderedScreenWidth);
		  if (PPUPack.IPPU.Clip [0].Count [5])
                    {
		      uint32 *p = (uint32 *) (GFX.SubScreen + y * GFX.Pitch2);
		      uint32 *q = (uint32 *) ((uint16 *) p + PPUPack.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 (PPUPack.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,
			      PPUPack.IPPU.RenderedScreenWidth);
		  memset (GFX.SubZBuffer + y * GFX.ZPitch, 1,
			  PPUPack.IPPU.RenderedScreenWidth);

		  if (PPUPack.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 + PPUPack.IPPU.RenderedScreenWidth);

		      while (p < q)	*p++ = b;
		    }
		}
	    }
	  if (ANYTHING_ON_SUB)
	    {
	      GFX.DB = GFX.SubZBuffer;
	      RenderScreen (GFX.SubScreen, TRUE, TRUE, SUB_SCREEN_DEPTH);
	    }

	  if (PPUPack.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 + PPUPack.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 = PPUPack.IPPU.ScreenColors [0];
	      uint32 Left = 0;
	      uint32 Right = 256;
	      uint32 Count;

	      pClip = &PPUPack.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++;
				    }
				}
			    }
		    }
		}
	    }
	  else
	    {
	      // Subscreen not being added to back
	      uint32 back = PPUPack.IPPU.ScreenColors [0] | (PPUPack.IPPU.ScreenColors [0] << 16);
	      pClip = &PPUPack.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++;
			}
		    }
		}
	    }
	}
      else
	{
	  // 16bit and transparency but currently no transparency effects in
	  // operation.

	  uint32 back = PPUPack.IPPU.ScreenColors [0] |
	    (PPUPack.IPPU.ScreenColors [0] << 16);

	  if (PPUPack.PPU.ForcedBlanking)
	    back = black;

	  if (PPUPack.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 + PPUPack.IPPU.RenderedScreenWidth);

		  while (p < q)
		    *p++ = black;

		  for (uint32 c = 0; c < PPUPack.IPPU.Clip [0].Count [5]; c++)
		    {
		      if (PPUPack.IPPU.Clip [0].Right [c][5] > PPUPack.IPPU.Clip [0].Left [c][5])
			{
			  uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
			  uint16 *q = p + PPUPack.IPPU.Clip [0].Right [c][5] * x2;
			  p += PPUPack.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 + PPUPack.IPPU.RenderedScreenWidth);
		  while (p < q)
		    *p++ = back;
		}
	    }
	  if (!PPUPack.PPU.ForcedBlanking)
	    {
	      for (uint32 y = starty; y <= endy; y++)
		{
		  ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch,
			      PPUPack.IPPU.RenderedScreenWidth);
		}
	      GFX.DB = GFX.ZBuffer;
	      RenderScreen (GFX.Screen, FALSE, TRUE, SUB_SCREEN_DEPTH);
	    }
	}


  PPUPack.IPPU.PreviousLine = PPUPack.IPPU.CurrentLine;
}

#ifdef GFX_MULTI_FORMAT

#define _BUILD_PIXEL(F) \
uint32 BuildPixel##F(uint32 R, uint32 G, uint32 B) \
{ \
    return (BUILD_PIXEL_##F(R,G,B)); \
}\
uint32 BuildPixel2##F(uint32 R, uint32 G, uint32 B) \
{ \
    return (BUILD_PIXEL2_##F(R,G,B)); \
} \
void DecomposePixel##F(uint32 pixel, uint32 &R, uint32 &G, uint32 &B) \
{ \
    DECOMPOSE_PIXEL_##F(pixel,R,G,B); \
}

_BUILD_PIXEL(RGB565)
_BUILD_PIXEL(RGB555)
_BUILD_PIXEL(BGR565)
_BUILD_PIXEL(BGR555)
_BUILD_PIXEL(GBR565)
_BUILD_PIXEL(GBR555)
_BUILD_PIXEL(RGB5551)

bool8 S9xSetRenderPixelFormat (int format)
{
    extern uint32 current_graphic_format;

    current_graphic_format = format;

    switch (format)
    {
    case RGB565:
	_BUILD_SETUP(RGB565)
	return (TRUE);
    case RGB555:
	_BUILD_SETUP(RGB555)
	return (TRUE);
    case BGR565:
	_BUILD_SETUP(BGR565)
	return (TRUE);
    case BGR555:
	_BUILD_SETUP(BGR555)
	return (TRUE);
    case GBR565:
	_BUILD_SETUP(GBR565)
	return (TRUE);
    case GBR555:
	_BUILD_SETUP(GBR555)
	return (TRUE);
    case RGB5551:
        _BUILD_SETUP(RGB5551)
        return (TRUE);
    default:
	break;
    }
    return (FALSE);
}
#endif


