📄 clip.cpp
字号:
/* * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. * * (c) Copyright 1996 - 2001 Gary Henderson (gary@daniver.demon.co.uk) 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@daniver.demon.co.uk). * * DOS port code contains the works of other authors. See headers in * individual files. * * Snes9x homepage: 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 <stdlib.h>#include "snes9x.h"#include "memmap.h"#include "ppu.h"struct Band{ uint32 Left; uint32 Right;};#undef MIN#undef MAX#define MIN(A,B) ((A) < (B) ? (A) : (B))#define MAX(A,B) ((A) > (B) ? (A) : (B))#define BAND_EMPTY(B) (B.Left >= B.Right)#define BANDS_INTERSECT(A,B) ((A.Left >= B.Left && A.Left < B.Right) || \ (A.Right > B.Left && A.Right <= B.Right))#define OR_BANDS(R,A,B) {\ R.Left = MIN(A.Left, B.Left); \ R.Right = MAX(A.Right, B.Right);} #define AND_BANDS(R,A,B) {\ R.Left = MAX(A.Left, B.Left); \ R.Right = MIN(A.Right, B.Right);}static int IntCompare (const void *d1, const void *d2){ if (*(uint32 *) d1 > *(uint32 *) d2) return (1); else if (*(uint32 *) d1 < *(uint32 *) d2) return (-1); return (0);}static int BandCompare (const void *d1, const void *d2){ if (((struct Band *) d1)->Left > ((struct Band *) d2)->Left) return (1); else if (((struct Band *) d1)->Left < ((struct Band *) d2)->Left) return (-1); return (0);}void ComputeClipWindows (){ struct ClipData *pClip = &IPPU.Clip [0]; // Loop around the main screen then the sub-screen. for (int c = 0; c < 2; c++, pClip++) { // Loop around the colour window then a clip window for each of the // background layers. for (int w = 5; w >= 0; w--) { pClip->Count[w] = 0; if (w == 5) // The colour window... { if (c == 0) // ... on the main screen { if ((Memory.FillRAM [0x2130] & 0xc0) == 0xc0) { // The whole of the main screen is switched off, // completely clip everything. for (int i = 0; i < 6; i++) { IPPU.Clip [c].Count [i] = 1; IPPU.Clip [c].Left [0][i] = 1; IPPU.Clip [c].Right [0][i] = 0; } continue; } else if ((Memory.FillRAM [0x2130] & 0xc0) == 0x00) continue; } else { // .. colour window on the sub-screen. if ((Memory.FillRAM [0x2130] & 0x30) == 0x30) { // The sub-screen is switched off, completely // clip everything. for (int i = 0; i < 6; i++) { IPPU.Clip [1].Count [i] = 1; IPPU.Clip [1].Left [0][i] = 1; IPPU.Clip [1].Right [0][i] = 0; } return; } else if ((Memory.FillRAM [0x2130] & 0x30) == 0x00) continue; } } if (!Settings.DisableGraphicWindows) { if (w == 5 || pClip->Count [5] || (Memory.FillRAM [0x212c + c] & Memory.FillRAM [0x212e + c] & (1 << w))) { struct Band Win1[3]; struct Band Win2[3]; uint32 Window1Enabled = 0; uint32 Window2Enabled = 0; bool8 invert = (w == 5 && ((c == 1 && (Memory.FillRAM [0x2130] & 0x30) == 0x10) || (c == 0 && (Memory.FillRAM [0x2130] & 0xc0) == 0x40))); if (w == 5 || (Memory.FillRAM [0x212c + c] & Memory.FillRAM [0x212e + c] & (1 << w))) { if (PPU.ClipWindow1Enable [w]) { if (!PPU.ClipWindow1Inside [w]) { Win1[Window1Enabled].Left = PPU.Window1Left; Win1[Window1Enabled++].Right = PPU.Window1Right + 1; } else { if (PPU.Window1Left <= PPU.Window1Right) { if (PPU.Window1Left > 0) { Win1[Window1Enabled].Left = 0; Win1[Window1Enabled++].Right = PPU.Window1Left; } if (PPU.Window1Right < 255) { Win1[Window1Enabled].Left = PPU.Window1Right + 1; Win1[Window1Enabled++].Right = 256; } if (Window1Enabled == 0) { Win1[Window1Enabled].Left = 1; Win1[Window1Enabled++].Right = 0; } } else { // 'outside' a window with no range - // appears to be the whole screen. Win1[Window1Enabled].Left = 0; Win1[Window1Enabled++].Right = 256; } } } if (PPU.ClipWindow2Enable [w]) { if (!PPU.ClipWindow2Inside [w]) { Win2[Window2Enabled].Left = PPU.Window2Left; Win2[Window2Enabled++].Right = PPU.Window2Right + 1; } else { if (PPU.Window2Left <= PPU.Window2Right) { if (PPU.Window2Left > 0) { Win2[Window2Enabled].Left = 0; Win2[Window2Enabled++].Right = PPU.Window2Left; } if (PPU.Window2Right < 255) { Win2[Window2Enabled].Left = PPU.Window2Right + 1; Win2[Window2Enabled++].Right = 256; } if (Window2Enabled == 0) { Win2[Window2Enabled].Left = 1; Win2[Window2Enabled++].Right = 0; } } else { Win2[Window2Enabled].Left = 0; Win2[Window2Enabled++].Right = 256; } } } } if (Window1Enabled && Window2Enabled) { // Overlap logic // // Each window will be in one of three states: // 1. <no range> (Left > Right. One band) // 2. | ---------------- | (Left >= 0, Right <= 255, Left <= Right. One band) // 3. |------------ ----------| (Left1 == 0, Right1 < Left2; Left2 > Right1, Right2 == 255. Two bands) struct Band Bands [6]; int B = 0; switch (PPU.ClipWindowOverlapLogic [w] ^ 1) { case CLIP_OR: if (Window1Enabled == 1) { if (BAND_EMPTY(Win1[0])) { B = Window2Enabled; memmove (Bands, Win2, sizeof(Win2[0]) * Window2Enabled); } else { if (Window2Enabled == 1) { if (BAND_EMPTY (Win2[0])) Bands[B++] = Win1[0]; else { if (BANDS_INTERSECT (Win1[0], Win2[0])) { OR_BANDS(Bands[0],Win1[0], Win2[0]) B = 1; } else { Bands[B++] = Win1[0]; Bands[B++] = Win2[0]; } } } else { if (BANDS_INTERSECT(Win1[0], Win2[0])) { OR_BANDS(Bands[0], Win1[0], Win2[0]) if (BANDS_INTERSECT(Win1[0], Win2[1])) OR_BANDS(Bands[1], Win1[0], Win2[1]) else Bands[1] = Win2[1]; B = 1; if (BANDS_INTERSECT(Bands[0], Bands[1])) OR_BANDS(Bands[0], Bands[0], Bands[1]) else B = 2; } else if (BANDS_INTERSECT(Win1[0], Win2[1])) { Bands[B++] = Win2[0]; OR_BANDS(Bands[B], Win1[0], Win2[1]); B++; } else { Bands[0] = Win2[0]; Bands[1] = Win1[0]; Bands[2] = Win2[1]; B = 3; } } } } else if (Window2Enabled == 1) { if (BAND_EMPTY(Win2[0])) { // Window 2 defines an empty range - just // use window 1 as the clipping (which // could also be empty). B = Window1Enabled; memmove (Bands, Win1, sizeof(Win1[0]) * Window1Enabled); } else { // Window 1 has two bands and Window 2 has one. // Neither is an empty region. if (BANDS_INTERSECT(Win2[0], Win1[0])) { OR_BANDS(Bands[0], Win2[0], Win1[0]) if (BANDS_INTERSECT(Win2[0], Win1[1])) OR_BANDS(Bands[1], Win2[0], Win1[1]) else Bands[1] = Win1[1]; B = 1; if (BANDS_INTERSECT(Bands[0], Bands[1])) OR_BANDS(Bands[0], Bands[0], Bands[1]) else B = 2; } else if (BANDS_INTERSECT(Win2[0], Win1[1])) { Bands[B++] = Win1[0]; OR_BANDS(Bands[B], Win2[0], Win1[1]); B++; } else { Bands[0] = Win1[0]; Bands[1] = Win2[0]; Bands[2] = Win1[1]; B = 3; } } } else { // Both windows have two bands OR_BANDS(Bands[0], Win1[0], Win2[0]); OR_BANDS(Bands[1], Win1[1], Win2[1]); B = 1; if (BANDS_INTERSECT(Bands[0], Bands[1])) OR_BANDS(Bands[0], Bands[0], Bands[1]) else B = 2; } break; case CLIP_AND: if (Window1Enabled == 1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -