Esempio n. 1
0
        public VPC(PCEngine pce, VDC vdc1, VDC vdc2, VCE vce, HuC6280 cpu)
        {
            PCE  = pce;
            VDC1 = vdc1;
            VDC2 = vdc2;
            VCE  = vce;
            CPU  = cpu;

            // latch initial video buffer
            FrameBuffer = vdc1.GetVideoBuffer();
            FrameWidth  = vdc1.BufferWidth;
            FrameHeight = vdc1.BufferHeight;
        }
Esempio n. 2
0
		public VPC(PCEngine pce, VDC vdc1, VDC vdc2, VCE vce, HuC6280 cpu)
		{
			PCE = pce;
			VDC1 = vdc1;
			VDC2 = vdc2;
			VCE = vce;
			CPU = cpu;

			// latch initial video buffer
			FrameBuffer = vdc1.GetVideoBuffer();
			FrameWidth = vdc1.BufferWidth;
			FrameHeight = vdc1.BufferHeight;
		}
        private void Init(GameInfo game, byte[] rom)
        {
            Cpu  = new HuC6280(MemoryCallbacks);
            VCE  = new VCE();
            VDC1 = new VDC(this, Cpu, VCE);
            PSG  = new HuC6280PSG(735);
            SCSI = new ScsiCDBus(this, disc);

            Cpu.Logger = s => Tracer.Put(s);

            if (TurboGrafx)
            {
                Ram = new byte[0x2000];
                Cpu.ReadMemory21  = ReadMemory;
                Cpu.WriteMemory21 = WriteMemory;
                Cpu.WriteVDC      = VDC1.WriteVDC;
                _soundProvider    = PSG;
                CDAudio           = new CDAudio(null, 0);
            }

            else if (SuperGrafx)
            {
                VDC2              = new VDC(this, Cpu, VCE);
                VPC               = new VPC(this, VDC1, VDC2, VCE, Cpu);
                Ram               = new byte[0x8000];
                Cpu.ReadMemory21  = ReadMemorySGX;
                Cpu.WriteMemory21 = WriteMemorySGX;
                Cpu.WriteVDC      = VDC1.WriteVDC;
                _soundProvider    = PSG;
                CDAudio           = new CDAudio(null, 0);
            }

            else if (TurboCD)
            {
                Ram               = new byte[0x2000];
                CDRam             = new byte[0x10000];
                ADPCM             = new ADPCM(this, SCSI);
                Cpu.ReadMemory21  = ReadMemoryCD;
                Cpu.WriteMemory21 = WriteMemoryCD;
                Cpu.WriteVDC      = VDC1.WriteVDC;
                CDAudio           = new CDAudio(disc);
                SetCDAudioCallback();
                PSG.MaxVolume   = short.MaxValue * 3 / 4;
                SoundMixer      = new SoundMixer(735, PSG, CDAudio, ADPCM);
                _soundProvider  = SoundMixer;
                Cpu.ThinkAction = cycles => { SCSI.Think(); ADPCM.Think(cycles); };
            }

            if (rom.Length == 0x60000)
            {
                // 384k roms require special loading code. Why ;_;
                // In memory, 384k roms look like [1st 256k][Then full 384k]
                RomData = new byte[0xA0000];
                var origRom = rom;
                for (int i = 0; i < 0x40000; i++)
                {
                    RomData[i] = origRom[i];
                }
                for (int i = 0; i < 0x60000; i++)
                {
                    RomData[i + 0x40000] = origRom[i];
                }
                RomLength = RomData.Length;
            }
            else if (rom.Length > 1024 * 1024)
            {
                // If the rom is bigger than 1 megabyte, switch to Street Fighter 2 mapper
                Cpu.ReadMemory21  = ReadMemorySF2;
                Cpu.WriteMemory21 = WriteMemorySF2;
                RomData           = rom;
                RomLength         = RomData.Length;

                // user request: current value of the SF2MapperLatch on the tracelogger
                Cpu.Logger = s => Tracer.Put(new TraceInfo
                {
                    Disassembly  = $"{SF2MapperLatch:X1}:{s}",
                    RegisterInfo = ""
                });
            }
            else
            {
                // normal rom.
                RomData   = rom;
                RomLength = RomData.Length;
            }

            if (game["BRAM"] || Type == NecSystemType.TurboCD)
            {
                BramEnabled = true;
                BRAM        = new byte[2048];

                // pre-format BRAM. damn are we helpful.
                BRAM[0] = 0x48; BRAM[1] = 0x55; BRAM[2] = 0x42; BRAM[3] = 0x4D;
                BRAM[4] = 0x00; BRAM[5] = 0x88; BRAM[6] = 0x10; BRAM[7] = 0x80;
            }

            if (game["SuperSysCard"])
            {
                SuperRam = new byte[0x30000];
            }

            if (game["ArcadeCard"])
            {
                ArcadeRam            = new byte[0x200000];
                ArcadeCard           = true;
                ArcadeCardRewindHack = Settings.ArcadeCardRewindHack;
                for (int i = 0; i < 4; i++)
                {
                    ArcadePage[i] = new ArcadeCardPage();
                }
            }

            if (game["PopulousSRAM"])
            {
                PopulousRAM       = new byte[0x8000];
                Cpu.ReadMemory21  = ReadMemoryPopulous;
                Cpu.WriteMemory21 = WriteMemoryPopulous;
            }

            // the gamedb can force sprite limit on, ignoring settings
            if (game["ForceSpriteLimit"] || game.NotInDatabase)
            {
                ForceSpriteLimit = true;
            }

            if (game["CdVol"])
            {
                CDAudio.MaxVolume = int.Parse(game.OptionValue("CdVol"));
            }

            if (game["PsgVol"])
            {
                PSG.MaxVolume = int.Parse(game.OptionValue("PsgVol"));
            }

            if (game["AdpcmVol"])
            {
                ADPCM.MaxVolume = int.Parse(game.OptionValue("AdpcmVol"));
            }

            // the gamedb can also force equalizevolumes on
            if (TurboCD && (Settings.EqualizeVolume || game["EqualizeVolumes"] || game.NotInDatabase))
            {
                SoundMixer.EqualizeVolumes();
            }

            // Ok, yes, HBlankPeriod's only purpose is game-specific hax.
            // 1) At least they're not coded directly into the emulator, but instead data-driven.
            // 2) The games which have custom HBlankPeriods work without it, the override only
            //    serves to clean up minor gfx anomalies.
            // 3) There's no point in haxing the timing with incorrect values in an attempt to avoid this.
            //    The proper fix is cycle-accurate/bus-accurate timing. That isn't coming to the C#
            //    version of this core. Let's just acknolwedge that the timing is imperfect and fix
            //    it in the least intrusive and most honest way we can.
            if (game["HBlankPeriod"])
            {
                VDC1.HBlankCycles = game.GetIntValue("HBlankPeriod");
            }

            // This is also a hack. Proper multi-res/TV emulation will be a native-code core feature.
            if (game["MultiResHack"])
            {
                VDC1.MultiResHack = game.GetIntValue("MultiResHack");
            }

            Cpu.ResetPC();

            Tracer = new TraceBuffer {
                Header = Cpu.TraceHeader
            };
            var ser = new BasicServiceProvider(this);

            ServiceProvider = ser;
            ser.Register <ITraceable>(Tracer);
            ser.Register <IDisassemblable>(Cpu);
            ser.Register <IVideoProvider>((IVideoProvider)VPC ?? VDC1);
            ser.Register <ISoundProvider>(_soundProvider);
            ser.Register <IStatable>(new StateSerializer(SyncState));
            SetupMemoryDomains();
        }
Esempio n. 4
0
		private void checkBoxVDC2_CheckedChanged(object sender, EventArgs e)
		{
			vdc = checkBoxVDC2.Checked ? emu.VDC2 : emu.VDC1;
			UpdateValues();
		}
Esempio n. 5
0
        private void RenderSpritesScanline(VDC vdc, byte lowPriority, byte highPriority, bool show)
        {
            if (vdc.SpritesEnabled == false)
            {
                return;
            }

            // clear inter-sprite priority buffer
            Array.Clear(InterSpritePriorityBuffer, 0, FrameWidth);

            var testRange = new MutableIntRange(0, vdc.ActiveLine + 1);

            for (int i = 0; i < 64; i++)
            {
                int    y      = (vdc.SpriteAttributeTable[(i * 4) + 0] & 1023) - 64;
                int    x      = (vdc.SpriteAttributeTable[(i * 4) + 1] & 1023) - 32;
                ushort flags  = vdc.SpriteAttributeTable[(i * 4) + 3];
                byte   height = heightTable[(flags >> 12) & 3];
                testRange.Min = vdc.ActiveLine - height;
                if (!testRange.StrictContains(y))
                {
                    continue;
                }

                int  patternNo   = (((vdc.SpriteAttributeTable[(i * 4) + 2]) >> 1) & 0x1FF);
                int  paletteBase = 256 + ((flags & 15) * 16);
                int  width       = (flags & 0x100) == 0 ? 16 : 32;
                bool priority    = (flags & 0x80) != 0;
                bool hflip       = (flags & 0x0800) != 0;
                bool vflip       = (flags & 0x8000) != 0;

                if (width == 32)
                {
                    patternNo &= 0x1FE;
                }

                int yofs;
                if (vflip == false)
                {
                    yofs = (vdc.ActiveLine - y) & 15;
                    if (height == 32)
                    {
                        patternNo &= 0x1FD;
                        if (vdc.ActiveLine - y >= 16)
                        {
                            y         += 16;
                            patternNo += 2;
                        }
                    }
                    else if (height == 64)
                    {
                        patternNo &= 0x1F9;
                        if (vdc.ActiveLine - y >= 48)
                        {
                            y         += 48;
                            patternNo += 6;
                        }
                        else if (vdc.ActiveLine - y >= 32)
                        {
                            y         += 32;
                            patternNo += 4;
                        }
                        else if (vdc.ActiveLine - y >= 16)
                        {
                            y         += 16;
                            patternNo += 2;
                        }
                    }
                }
                else                 // vflip == true
                {
                    yofs = 15 - ((vdc.ActiveLine - y) & 15);
                    if (height == 32)
                    {
                        patternNo &= 0x1FD;
                        if (vdc.ActiveLine - y < 16)
                        {
                            y         += 16;
                            patternNo += 2;
                        }
                    }
                    else if (height == 64)
                    {
                        patternNo &= 0x1F9;
                        if (vdc.ActiveLine - y < 16)
                        {
                            y         += 48;
                            patternNo += 6;
                        }
                        else if (vdc.ActiveLine - y < 32)
                        {
                            y         += 32;
                            patternNo += 4;
                        }
                        else if (vdc.ActiveLine - y < 48)
                        {
                            y         += 16;
                            patternNo += 2;
                        }
                    }
                }
                if (hflip == false)
                {
                    if (x + width > 0 && y + height > 0)
                    {
                        for (int xs = x >= 0 ? x : 0; xs < x + 16 && xs >= 0 && xs < FrameWidth; xs++)
                        {
                            byte pixel = vdc.SpriteBuffer[(patternNo * 256) + (yofs * 16) + (xs - x)];
                            if (pixel != 0 && InterSpritePriorityBuffer[xs] == 0)
                            {
                                InterSpritePriorityBuffer[xs] = 1;
                                byte myPriority = priority ? highPriority : lowPriority;
                                if (PriorityBuffer[xs] < myPriority)
                                {
                                    if (show)
                                    {
                                        FrameBuffer[((vdc.ActiveLine + vdc.ViewStartLine - PCE.Settings.Top_Line) * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
                                    }
                                    PriorityBuffer[xs] = myPriority;
                                }
                            }
                        }
                    }
                    if (width == 32)
                    {
                        patternNo++;
                        x += 16;
                        for (int xs = x >= 0 ? x : 0; xs < x + 16 && xs >= 0 && xs < FrameWidth; xs++)
                        {
                            byte pixel = vdc.SpriteBuffer[(patternNo * 256) + (yofs * 16) + (xs - x)];
                            if (pixel != 0 && InterSpritePriorityBuffer[xs] == 0)
                            {
                                InterSpritePriorityBuffer[xs] = 1;
                                byte myPriority = priority ? highPriority : lowPriority;
                                if (PriorityBuffer[xs] < myPriority)
                                {
                                    if (show)
                                    {
                                        FrameBuffer[((vdc.ActiveLine + vdc.ViewStartLine - PCE.Settings.Top_Line) * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
                                    }
                                    PriorityBuffer[xs] = myPriority;
                                }
                            }
                        }
                    }
                }
                else
                {                 // hflip = true
                    if (x + width > 0 && y + height > 0)
                    {
                        if (width == 32)
                        {
                            patternNo++;
                        }
                        for (int xs = x >= 0 ? x : 0; xs < x + 16 && xs >= 0 && xs < FrameWidth; xs++)
                        {
                            byte pixel = vdc.SpriteBuffer[(patternNo * 256) + (yofs * 16) + 15 - (xs - x)];
                            if (pixel != 0 && InterSpritePriorityBuffer[xs] == 0)
                            {
                                InterSpritePriorityBuffer[xs] = 1;
                                byte myPriority = priority ? highPriority : lowPriority;
                                if (PriorityBuffer[xs] < myPriority)
                                {
                                    if (show)
                                    {
                                        FrameBuffer[((vdc.ActiveLine + vdc.ViewStartLine - PCE.Settings.Top_Line) * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
                                    }
                                    PriorityBuffer[xs] = myPriority;
                                }
                            }
                        }
                        if (width == 32)
                        {
                            patternNo--;
                            x += 16;
                            for (int xs = x >= 0 ? x : 0; xs < x + 16 && xs >= 0 && xs < FrameWidth; xs++)
                            {
                                byte pixel = vdc.SpriteBuffer[(patternNo * 256) + (yofs * 16) + 15 - (xs - x)];
                                if (pixel != 0 && InterSpritePriorityBuffer[xs] == 0)
                                {
                                    InterSpritePriorityBuffer[xs] = 1;
                                    byte myPriority = priority ? highPriority : lowPriority;
                                    if (PriorityBuffer[xs] < myPriority)
                                    {
                                        if (show)
                                        {
                                            FrameBuffer[((vdc.ActiveLine + vdc.ViewStartLine - PCE.Settings.Top_Line) * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
                                        }
                                        PriorityBuffer[xs] = myPriority;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Esempio n. 6
0
        private unsafe void RenderBackgroundScanline(VDC vdc, byte priority, bool show)
        {
            if (vdc.BackgroundEnabled == false)
            {
                return;
            }

            // per-line parameters
            int vertLine = vdc.BackgroundY;

            vertLine %= vdc.BatHeight * 8;
            int yTile      = (vertLine / 8);
            int yOfs       = vertLine % 8;
            int xScroll    = vdc.Registers[BXR] & 0x3FF;
            int BatRowMask = vdc.BatWidth - 1;

            fixed(ushort *VRAMptr = vdc.VRAM)
            fixed(int *PALptr      = VCE.Palette)
            fixed(byte *Patternptr = vdc.PatternBuffer)
            fixed(int *FBptr       = FrameBuffer)
            fixed(byte *Priortyptr = PriorityBuffer)
            {
                // pointer to the BAT and the framebuffer for this line
                ushort *BatRow = VRAMptr + yTile * vdc.BatWidth;
                int *   dst    = FBptr + (vdc.ActiveLine + vdc.ViewStartLine - PCE.Settings.Top_Line) * FrameWidth;

                // parameters that change per tile
                ushort BatEnt;
                int    tileNo, paletteNo, paletteBase;
                byte * src;

                // calculate tile number and offset for first tile
                int xTile = (xScroll >> 3) & BatRowMask;
                int xOfs  = xScroll & 7;

                // update per-tile parameters for first tile
                BatEnt      = BatRow[xTile];
                tileNo      = BatEnt & 2047;
                paletteNo   = BatEnt >> 12;
                paletteBase = paletteNo * 16;
                src         = Patternptr + (tileNo << 6 | yOfs << 3 | xOfs);

                for (int x = 0; x < FrameWidth; x++)
                {
                    if (Priortyptr[x] < priority)
                    {
                        byte c = *src;
                        if (c != 0)
                        {
                            dst[x]        = show ? PALptr[paletteBase + c] : PALptr[0];
                            Priortyptr[x] = priority;
                        }
                    }
                    xOfs++;
                    src++;
                    if (xOfs == 8)
                    {
                        // update tile number
                        xOfs = 0;
                        xTile++;
                        xTile &= BatRowMask;
                        // update per-tile parameters
                        BatEnt      = BatRow[xTile];
                        tileNo      = BatEnt & 2047;
                        paletteNo   = BatEnt >> 12;
                        paletteBase = paletteNo * 16;
                        src         = Patternptr + (tileNo << 6 | yOfs << 3 | xOfs);
                    }
                }
            }
        }
Esempio n. 7
0
		void Init(GameInfo game, byte[] rom)
		{
			Controller = NullController.GetNullController();
			Cpu = new HuC6280(CoreComm);
			VCE = new VCE();
			VDC1 = new VDC(this, Cpu, VCE);
			PSG = new HuC6280PSG();
			SCSI = new ScsiCDBus(this, disc);

			Cpu.Logger = (s) => CoreComm.Tracer.Put(s);

			if (TurboGrafx)
			{
				Ram = new byte[0x2000];
				Cpu.ReadMemory21 = ReadMemory;
				Cpu.WriteMemory21 = WriteMemory;
				Cpu.WriteVDC = VDC1.WriteVDC;
				soundProvider = PSG;
				CDAudio = new CDAudio(null, 0);
			}

			else if (SuperGrafx)
			{
				VDC2 = new VDC(this, Cpu, VCE);
				VPC = new VPC(this, VDC1, VDC2, VCE, Cpu);
				Ram = new byte[0x8000];
				Cpu.ReadMemory21 = ReadMemorySGX;
				Cpu.WriteMemory21 = WriteMemorySGX;
				Cpu.WriteVDC = VDC1.WriteVDC;
				soundProvider = PSG;
				CDAudio = new CDAudio(null, 0);
			}

			else if (TurboCD)
			{
				Ram = new byte[0x2000];
				CDRam = new byte[0x10000];
				ADPCM = new ADPCM(this, SCSI);
				Cpu.ReadMemory21 = ReadMemoryCD;
				Cpu.WriteMemory21 = WriteMemoryCD;
				Cpu.WriteVDC = VDC1.WriteVDC;
				CDAudio = new CDAudio(disc);
				SetCDAudioCallback();
				PSG.MaxVolume = short.MaxValue * 3 / 4;
				SoundMixer = new SoundMixer(PSG, CDAudio, ADPCM);
				SoundSynchronizer = new MetaspuSoundProvider(ESynchMethod.ESynchMethod_V);
				soundProvider = SoundSynchronizer;
				Cpu.ThinkAction = (cycles) => { SCSI.Think(); ADPCM.Think(cycles); };
			}

			if (rom.Length == 0x60000)
			{
				// 384k roms require special loading code. Why ;_;
				// In memory, 384k roms look like [1st 256k][Then full 384k]
				RomData = new byte[0xA0000];
				var origRom = rom;
				for (int i = 0; i < 0x40000; i++)
					RomData[i] = origRom[i];
				for (int i = 0; i < 0x60000; i++)
					RomData[i + 0x40000] = origRom[i];
				RomLength = RomData.Length;
			}
			else if (rom.Length > 1024 * 1024)
			{
				// If the rom is bigger than 1 megabyte, switch to Street Fighter 2 mapper
				Cpu.ReadMemory21 = ReadMemorySF2;
				Cpu.WriteMemory21 = WriteMemorySF2;
				RomData = rom;
				RomLength = RomData.Length;
				// user request: current value of the SF2MapperLatch on the tracelogger
				Cpu.Logger = (s) => CoreComm.Tracer.Put(string.Format("{0:X1}:{1}", SF2MapperLatch, s));
			}
			else
			{
				// normal rom.
				RomData = rom;
				RomLength = RomData.Length;
			}

			if (game["BRAM"] || Type == NecSystemType.TurboCD)
			{
				BramEnabled = true;
				BRAM = new byte[2048];

				// pre-format BRAM. damn are we helpful.
				BRAM[0] = 0x48; BRAM[1] = 0x55; BRAM[2] = 0x42; BRAM[3] = 0x4D;
				BRAM[4] = 0x00; BRAM[5] = 0x88; BRAM[6] = 0x10; BRAM[7] = 0x80;
			}

			if (game["SuperSysCard"])
				SuperRam = new byte[0x30000];

			if (game["ArcadeCard"])
			{
				ArcadeRam = new byte[0x200000];
				ArcadeCard = true;
				ArcadeCardRewindHack = _settings.ArcadeCardRewindHack;
				for (int i = 0; i < 4; i++)
					ArcadePage[i] = new ArcadeCardPage();
			}

			if (game["PopulousSRAM"])
			{
				PopulousRAM = new byte[0x8000];
				Cpu.ReadMemory21 = ReadMemoryPopulous;
				Cpu.WriteMemory21 = WriteMemoryPopulous;
			}

			// the gamedb can force sprite limit on, ignoring settings
			if (game["ForceSpriteLimit"] || game.NotInDatabase)
				ForceSpriteLimit = true;

			if (game["CdVol"])
				CDAudio.MaxVolume = int.Parse(game.OptionValue("CdVol"));
			if (game["PsgVol"])
				PSG.MaxVolume = int.Parse(game.OptionValue("PsgVol"));
			if (game["AdpcmVol"])
				ADPCM.MaxVolume = int.Parse(game.OptionValue("AdpcmVol"));
			// the gamedb can also force equalizevolumes on
			if (TurboCD && (_settings.EqualizeVolume || game["EqualizeVolumes"] || game.NotInDatabase))
				SoundMixer.EqualizeVolumes();

			// Ok, yes, HBlankPeriod's only purpose is game-specific hax.
			// 1) At least they're not coded directly into the emulator, but instead data-driven.
			// 2) The games which have custom HBlankPeriods work without it, the override only
			//    serves to clean up minor gfx anomalies.
			// 3) There's no point in haxing the timing with incorrect values in an attempt to avoid this.
			//    The proper fix is cycle-accurate/bus-accurate timing. That isn't coming to the C# 
			//    version of this core. Let's just acknolwedge that the timing is imperfect and fix
			//    it in the least intrusive and most honest way we can.

			if (game["HBlankPeriod"])
				VDC1.HBlankCycles = game.GetIntValue("HBlankPeriod");

			// This is also a hack. Proper multi-res/TV emulation will be a native-code core feature.

			if (game["MultiResHack"])
				VDC1.MultiResHack = game.GetIntValue("MultiResHack");

			Cpu.ResetPC();
			SetupMemoryDomains();
		}
Esempio n. 8
0
		void RenderSpritesScanline(VDC vdc, byte lowPriority, byte highPriority, bool show)
		{
			if (vdc.SpritesEnabled == false)
				return;

			// clear inter-sprite priority buffer
			Array.Clear(InterSpritePriorityBuffer, 0, FrameWidth);

			for (int i = 0; i < 64; i++)
			{
				int y = (vdc.SpriteAttributeTable[(i * 4) + 0] & 1023) - 64;
				int x = (vdc.SpriteAttributeTable[(i * 4) + 1] & 1023) - 32;
				ushort flags = vdc.SpriteAttributeTable[(i * 4) + 3];
				int height = heightTable[(flags >> 12) & 3];

				if (y + height <= vdc.ActiveLine || y > vdc.ActiveLine)
					continue;

				int patternNo = (((vdc.SpriteAttributeTable[(i * 4) + 2]) >> 1) & 0x1FF);
				int paletteBase = 256 + ((flags & 15) * 16);
				int width = (flags & 0x100) == 0 ? 16 : 32;
				bool priority = (flags & 0x80) != 0;
				bool hflip = (flags & 0x0800) != 0;
				bool vflip = (flags & 0x8000) != 0;

				if (width == 32)
					patternNo &= 0x1FE;

				int yofs;
				if (vflip == false)
				{
					yofs = (vdc.ActiveLine - y) & 15;
					if (height == 32)
					{
						patternNo &= 0x1FD;
						if (vdc.ActiveLine - y >= 16)
						{
							y += 16;
							patternNo += 2;
						}
					}
					else if (height == 64)
					{
						patternNo &= 0x1F9;
						if (vdc.ActiveLine - y >= 48)
						{
							y += 48;
							patternNo += 6;
						}
						else if (vdc.ActiveLine - y >= 32)
						{
							y += 32;
							patternNo += 4;
						}
						else if (vdc.ActiveLine - y >= 16)
						{
							y += 16;
							patternNo += 2;
						}
					}
				}
				else // vflip == true
				{
					yofs = 15 - ((vdc.ActiveLine - y) & 15);
					if (height == 32)
					{
						patternNo &= 0x1FD;
						if (vdc.ActiveLine - y < 16)
						{
							y += 16;
							patternNo += 2;
						}
					}
					else if (height == 64)
					{
						patternNo &= 0x1F9;
						if (vdc.ActiveLine - y < 16)
						{
							y += 48;
							patternNo += 6;
						}
						else if (vdc.ActiveLine - y < 32)
						{
							y += 32;
							patternNo += 4;
						}
						else if (vdc.ActiveLine - y < 48)
						{
							y += 16;
							patternNo += 2;
						}
					}
				}
				if (hflip == false)
				{
					if (x + width > 0 && y + height > 0)
					{
						for (int xs = x >= 0 ? x : 0; xs < x + 16 && xs >= 0 && xs < FrameWidth; xs++)
						{
							byte pixel = vdc.SpriteBuffer[(patternNo * 256) + (yofs * 16) + (xs - x)];
							if (pixel != 0 && InterSpritePriorityBuffer[xs] == 0)
							{
								InterSpritePriorityBuffer[xs] = 1;
								byte myPriority = priority ? highPriority : lowPriority;
								if (PriorityBuffer[xs] < myPriority)
								{
									if (show) FrameBuffer[(vdc.ActiveLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
									PriorityBuffer[xs] = myPriority;
								}
							}
						}
					}
					if (width == 32)
					{
						patternNo++;
						x += 16;
						for (int xs = x >= 0 ? x : 0; xs < x + 16 && xs >= 0 && xs < FrameWidth; xs++)
						{
							byte pixel = vdc.SpriteBuffer[(patternNo * 256) + (yofs * 16) + (xs - x)];
							if (pixel != 0 && InterSpritePriorityBuffer[xs] == 0)
							{
								InterSpritePriorityBuffer[xs] = 1;
								byte myPriority = priority ? highPriority : lowPriority;
								if (PriorityBuffer[xs] < myPriority)
								{
									if (show) FrameBuffer[(vdc.ActiveLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
									PriorityBuffer[xs] = myPriority;
								}
							}
						}
					}
				}
				else
				{ // hflip = true
					if (x + width > 0 && y + height > 0)
					{
						if (width == 32)
							patternNo++;
						for (int xs = x >= 0 ? x : 0; xs < x + 16 && xs >= 0 && xs < FrameWidth; xs++)
						{
							byte pixel = vdc.SpriteBuffer[(patternNo * 256) + (yofs * 16) + 15 - (xs - x)];
							if (pixel != 0 && InterSpritePriorityBuffer[xs] == 0)
							{
								InterSpritePriorityBuffer[xs] = 1;
								byte myPriority = priority ? highPriority : lowPriority;
								if (PriorityBuffer[xs] < myPriority)
								{
									if (show) FrameBuffer[(vdc.ActiveLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
									PriorityBuffer[xs] = myPriority;
								}
							}
						}
						if (width == 32)
						{
							patternNo--;
							x += 16;
							for (int xs = x >= 0 ? x : 0; xs < x + 16 && xs >= 0 && xs < FrameWidth; xs++)
							{
								byte pixel = vdc.SpriteBuffer[(patternNo * 256) + (yofs * 16) + 15 - (xs - x)];
								if (pixel != 0 && InterSpritePriorityBuffer[xs] == 0)
								{
									InterSpritePriorityBuffer[xs] = 1;
									byte myPriority = priority ? highPriority : lowPriority;
									if (PriorityBuffer[xs] < myPriority)
									{
										if (show) FrameBuffer[(vdc.ActiveLine * FrameWidth) + xs] = VCE.Palette[paletteBase + pixel];
										PriorityBuffer[xs] = myPriority;
									}
								}
							}
						}
					}
				}
			}
		}
Esempio n. 9
0
		unsafe void RenderBackgroundScanline(VDC vdc, byte priority, bool show)
		{
			if (vdc.BackgroundEnabled == false)
				return;

			// per-line parameters
			int vertLine = vdc.BackgroundY;
			vertLine %= vdc.BatHeight * 8;
			int yTile = (vertLine / 8);
			int yOfs = vertLine % 8;
			int xScroll = vdc.Registers[BXR] & 0x3FF;
			int BatRowMask = vdc.BatWidth - 1;

			fixed (ushort* VRAMptr = vdc.VRAM)
			fixed (int* PALptr = VCE.Palette)
			fixed (byte* Patternptr = vdc.PatternBuffer)
			fixed (int* FBptr = FrameBuffer)
			fixed (byte* Priortyptr = PriorityBuffer)
			{
				// pointer to the BAT and the framebuffer for this line
				ushort* BatRow = VRAMptr + yTile * vdc.BatWidth;
				int* dst = FBptr + vdc.ActiveLine * FrameWidth;

				// parameters that change per tile
				ushort BatEnt;
				int tileNo, paletteNo, paletteBase;
				byte* src;

				// calculate tile number and offset for first tile
				int xTile = (xScroll >> 3) & BatRowMask;
				int xOfs = xScroll & 7;

				// update per-tile parameters for first tile
				BatEnt = BatRow[xTile];
				tileNo = BatEnt & 2047;
				paletteNo = BatEnt >> 12;
				paletteBase = paletteNo * 16;
				src = Patternptr + (tileNo << 6 | yOfs << 3 | xOfs);

				for (int x = 0; x < FrameWidth; x++)
				{
					if (Priortyptr[x] < priority)
					{
						byte c = *src;
						if (c != 0)
						{
							dst[x] = show ? PALptr[paletteBase + c] : PALptr[0];
							Priortyptr[x] = priority;
						}
					}
					xOfs++;
					src++;
					if (xOfs == 8)
					{
						// update tile number
						xOfs = 0;
						xTile++;
						xTile &= BatRowMask;
						// update per-tile parameters
						BatEnt = BatRow[xTile];
						tileNo = BatEnt & 2047;
						paletteNo = BatEnt >> 12;
						paletteBase = paletteNo * 16;
						src = Patternptr + (tileNo << 6 | yOfs << 3 | xOfs);
					}
				}
			}
		}