PageRenderTime 60ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 2ms

/source/gfx.cpp

https://github.com/alexinfurs/CATSFC
C++ | 4230 lines | 3596 code | 355 blank | 279 comment | 826 complexity | 508184a57c26da15f8ba2e2eb9be48c1 MD5 | raw file
Possible License(s): CC-BY-SA-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*******************************************************************************
  2. Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
  3. (c) Copyright 1996 - 2002 Gary Henderson (gary.henderson@ntlworld.com) and
  4. Jerremy Koot (jkoot@snes9x.com)
  5. (c) Copyright 2001 - 2004 John Weidman (jweidman@slip.net)
  6. (c) Copyright 2002 - 2004 Brad Jorsch (anomie@users.sourceforge.net),
  7. funkyass (funkyass@spam.shaw.ca),
  8. Joel Yliluoma (http://iki.fi/bisqwit/)
  9. Kris Bleakley (codeviolation@hotmail.com),
  10. Matthew Kendora,
  11. Nach (n-a-c-h@users.sourceforge.net),
  12. Peter Bortas (peter@bortas.org) and
  13. zones (kasumitokoduck@yahoo.com)
  14. C4 x86 assembler and some C emulation code
  15. (c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com),
  16. _Demo_ (_demo_@zsnes.com), and Nach
  17. C4 C++ code
  18. (c) Copyright 2003 Brad Jorsch
  19. DSP-1 emulator code
  20. (c) Copyright 1998 - 2004 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson,
  21. John Weidman, neviksti (neviksti@hotmail.com),
  22. Kris Bleakley, Andreas Naive
  23. DSP-2 emulator code
  24. (c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and
  25. Lord Nightmare (lord_nightmare@users.sourceforge.net
  26. OBC1 emulator code
  27. (c) Copyright 2001 - 2004 zsKnight, pagefault (pagefault@zsnes.com) and
  28. Kris Bleakley
  29. Ported from x86 assembler to C by sanmaiwashi
  30. SPC7110 and RTC C++ emulator code
  31. (c) Copyright 2002 Matthew Kendora with research by
  32. zsKnight, John Weidman, and Dark Force
  33. S-DD1 C emulator code
  34. (c) Copyright 2003 Brad Jorsch with research by
  35. Andreas Naive and John Weidman
  36. S-RTC C emulator code
  37. (c) Copyright 2001 John Weidman
  38. ST010 C++ emulator code
  39. (c) Copyright 2003 Feather, Kris Bleakley, John Weidman and Matthew Kendora
  40. Super FX x86 assembler emulator code
  41. (c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
  42. Super FX C emulator code
  43. (c) Copyright 1997 - 1999 Ivar, Gary Henderson and John Weidman
  44. SH assembler code partly based on x86 assembler code
  45. (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se)
  46. Specific ports contains the works of other authors. See headers in
  47. individual files.
  48. Snes9x homepage: http://www.snes9x.com
  49. Permission to use, copy, modify and distribute Snes9x in both binary and
  50. source form, for non-commercial purposes, is hereby granted without fee,
  51. providing that this license information and copyright notice appear with
  52. all copies and any derived work.
  53. This software is provided 'as-is', without any express or implied
  54. warranty. In no event shall the authors be held liable for any damages
  55. arising from the use of this software.
  56. Snes9x is freeware for PERSONAL USE only. Commercial users should
  57. seek permission of the copyright holders first. Commercial use includes
  58. charging money for Snes9x or software derived from Snes9x.
  59. The copyright holders request that bug fixes and improvements to the code
  60. should be forwarded to them so everyone can benefit from the modifications
  61. in future versions.
  62. Super NES and Super Nintendo Entertainment System are trademarks of
  63. Nintendo Co., Limited and its subsidiary companies.
  64. *******************************************************************************/
  65. #include "snes9x.h"
  66. #include "memmap.h"
  67. #include "ppu.h"
  68. #include "cpuexec.h"
  69. #include "display.h"
  70. #include "gfx.h"
  71. #include "apu.h"
  72. #include "cheats.h"
  73. #include "screenshot.h"
  74. #define M7 19
  75. #define M8 19
  76. void output_png();
  77. void ComputeClipWindows ();
  78. static void S9xDisplayFrameRate ();
  79. static void S9xDisplayString (const char *string);
  80. extern uint8 BitShifts[8][4];
  81. extern uint8 TileShifts[8][4];
  82. extern uint8 PaletteShifts[8][4];
  83. extern uint8 PaletteMasks[8][4];
  84. extern uint8 Depths[8][4];
  85. extern uint8 BGSizes [2];
  86. extern NormalTileRenderer DrawTilePtr;
  87. extern ClippedTileRenderer DrawClippedTilePtr;
  88. extern NormalTileRenderer DrawHiResTilePtr;
  89. extern ClippedTileRenderer DrawHiResClippedTilePtr;
  90. extern LargePixelRenderer DrawLargePixelPtr;
  91. extern struct SBG BG;
  92. extern struct SLineData LineData[240];
  93. extern struct SLineMatrixData LineMatrixData [240];
  94. extern uint8 Mode7Depths [2];
  95. #define CLIP_10_BIT_SIGNED(a) \
  96. ((a) & ((1 << 10) - 1)) + (((((a) & (1 << 13)) ^ (1 << 13)) - (1 << 13)) >> 3)
  97. #define ON_MAIN(N) \
  98. (GFX.r212c & (1 << (N)) && \
  99. !(PPU.BG_Forced & (1 << (N))))
  100. #define SUB_OR_ADD(N) \
  101. (GFX.r2131 & (1 << (N)))
  102. #define ON_SUB(N) \
  103. ((GFX.r2130 & 0x30) != 0x30 && \
  104. (GFX.r2130 & 2) && \
  105. (GFX.r212d & (1 << N)) && \
  106. !(PPU.BG_Forced & (1 << (N))))
  107. #define ANYTHING_ON_SUB \
  108. ((GFX.r2130 & 0x30) != 0x30 && \
  109. (GFX.r2130 & 2) && \
  110. (GFX.r212d & 0x1f))
  111. #define ADD_OR_SUB_ON_ANYTHING \
  112. (GFX.r2131 & 0x3f)
  113. #define FIX_INTERLACE(SCREEN, DO_DEPTH, DEPTH) \
  114. if (IPPU.DoubleHeightPixels && ((PPU.BGMode != 5 && PPU.BGMode != 6) || !IPPU.Interlace)) \
  115. for (uint32 y = GFX.StartY; y <= GFX.EndY; y++) \
  116. { \
  117. /* memmove converted: Same malloc, non-overlapping addresses [Neb] */ \
  118. memcpy (SCREEN + (y * 2 + 1) * GFX.Pitch2, \
  119. SCREEN + y * 2 * GFX.Pitch2, \
  120. GFX.Pitch2); \
  121. if(DO_DEPTH){ \
  122. /* memmove required: Same malloc, potentially overlapping addresses [Neb] */ \
  123. memmove (DEPTH + (y * 2 + 1) * (GFX.PPLx2>>1), \
  124. DEPTH + y * GFX.PPL, \
  125. GFX.PPLx2>>1); \
  126. } \
  127. }
  128. #define BLACK BUILD_PIXEL(0,0,0)
  129. #ifndef FOREVER_16_BIT
  130. void DrawTile (uint32 Tile, uint32 Offset, uint32 StartLine,
  131. uint32 LineCount);
  132. void DrawClippedTile (uint32 Tile, uint32 Offset,
  133. uint32 StartPixel, uint32 Width,
  134. uint32 StartLine, uint32 LineCount);
  135. void DrawTileHalfWidth (uint32 Tile, uint32 Offset, uint32 StartLine,
  136. uint32 LineCount);
  137. void DrawClippedTileHalfWidth (uint32 Tile, uint32 Offset,
  138. uint32 StartPixel, uint32 Width,
  139. uint32 StartLine, uint32 LineCount);
  140. void DrawTilex2 (uint32 Tile, uint32 Offset, uint32 StartLine,
  141. uint32 LineCount);
  142. void DrawClippedTilex2 (uint32 Tile, uint32 Offset,
  143. uint32 StartPixel, uint32 Width,
  144. uint32 StartLine, uint32 LineCount);
  145. void DrawTilex2x2 (uint32 Tile, uint32 Offset, uint32 StartLine,
  146. uint32 LineCount);
  147. void DrawClippedTilex2x2 (uint32 Tile, uint32 Offset,
  148. uint32 StartPixel, uint32 Width,
  149. uint32 StartLine, uint32 LineCount);
  150. void DrawLargePixel (uint32 Tile, uint32 Offset,
  151. uint32 StartPixel, uint32 Pixels,
  152. uint32 StartLine, uint32 LineCount);
  153. void DrawLargePixelHalfWidth (uint32 Tile, uint32 Offset,
  154. uint32 StartPixel, uint32 Pixels,
  155. uint32 StartLine, uint32 LineCount);
  156. #endif
  157. void DrawTile16 (uint32 Tile, uint32 Offset, uint32 StartLine,
  158. uint32 LineCount);
  159. void DrawClippedTile16 (uint32 Tile, uint32 Offset,
  160. uint32 StartPixel, uint32 Width,
  161. uint32 StartLine, uint32 LineCount);
  162. void DrawTile16HalfWidth (uint32 Tile, uint32 Offset, uint32 StartLine,
  163. uint32 LineCount);
  164. void DrawClippedTile16HalfWidth (uint32 Tile, uint32 Offset,
  165. uint32 StartPixel, uint32 Width,
  166. uint32 StartLine, uint32 LineCount);
  167. void DrawTile16x2 (uint32 Tile, uint32 Offset, uint32 StartLine,
  168. uint32 LineCount);
  169. void DrawClippedTile16x2 (uint32 Tile, uint32 Offset,
  170. uint32 StartPixel, uint32 Width,
  171. uint32 StartLine, uint32 LineCount);
  172. void DrawTile16x2x2 (uint32 Tile, uint32 Offset, uint32 StartLine,
  173. uint32 LineCount);
  174. void DrawClippedTile16x2x2 (uint32 Tile, uint32 Offset,
  175. uint32 StartPixel, uint32 Width,
  176. uint32 StartLine, uint32 LineCount);
  177. void DrawLargePixel16 (uint32 Tile, uint32 Offset,
  178. uint32 StartPixel, uint32 Pixels,
  179. uint32 StartLine, uint32 LineCount);
  180. void DrawLargePixel16HalfWidth (uint32 Tile, uint32 Offset,
  181. uint32 StartPixel, uint32 Pixels,
  182. uint32 StartLine, uint32 LineCount);
  183. void DrawTile16Add (uint32 Tile, uint32 Offset, uint32 StartLine,
  184. uint32 LineCount);
  185. void DrawClippedTile16Add (uint32 Tile, uint32 Offset,
  186. uint32 StartPixel, uint32 Width,
  187. uint32 StartLine, uint32 LineCount);
  188. void DrawTile16Add1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
  189. uint32 LineCount);
  190. void DrawClippedTile16Add1_2 (uint32 Tile, uint32 Offset,
  191. uint32 StartPixel, uint32 Width,
  192. uint32 StartLine, uint32 LineCount);
  193. void DrawTile16FixedAdd1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
  194. uint32 LineCount);
  195. void DrawClippedTile16FixedAdd1_2 (uint32 Tile, uint32 Offset,
  196. uint32 StartPixel, uint32 Width,
  197. uint32 StartLine, uint32 LineCount);
  198. void DrawTile16Sub (uint32 Tile, uint32 Offset, uint32 StartLine,
  199. uint32 LineCount);
  200. void DrawClippedTile16Sub (uint32 Tile, uint32 Offset,
  201. uint32 StartPixel, uint32 Width,
  202. uint32 StartLine, uint32 LineCount);
  203. void DrawTile16Sub1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
  204. uint32 LineCount);
  205. void DrawClippedTile16Sub1_2 (uint32 Tile, uint32 Offset,
  206. uint32 StartPixel, uint32 Width,
  207. uint32 StartLine, uint32 LineCount);
  208. void DrawTile16FixedSub1_2 (uint32 Tile, uint32 Offset, uint32 StartLine,
  209. uint32 LineCount);
  210. void DrawClippedTile16FixedSub1_2 (uint32 Tile, uint32 Offset,
  211. uint32 StartPixel, uint32 Width,
  212. uint32 StartLine, uint32 LineCount);
  213. void DrawLargePixel16Add (uint32 Tile, uint32 Offset,
  214. uint32 StartPixel, uint32 Pixels,
  215. uint32 StartLine, uint32 LineCount);
  216. void DrawLargePixel16Add1_2 (uint32 Tile, uint32 Offset,
  217. uint32 StartPixel, uint32 Pixels,
  218. uint32 StartLine, uint32 LineCount);
  219. void DrawLargePixel16Sub (uint32 Tile, uint32 Offset,
  220. uint32 StartPixel, uint32 Pixels,
  221. uint32 StartLine, uint32 LineCount);
  222. void DrawLargePixel16Sub1_2 (uint32 Tile, uint32 Offset,
  223. uint32 StartPixel, uint32 Pixels,
  224. uint32 StartLine, uint32 LineCount);
  225. bool8 S9xGraphicsInit ()
  226. {
  227. register uint32 PixelOdd = 1;
  228. register uint32 PixelEven = 2;
  229. #ifdef GFX_MULTI_FORMAT
  230. if (GFX.BuildPixel == NULL)
  231. S9xSetRenderPixelFormat (RGB565);
  232. #endif
  233. for (uint8 bitshift = 0; bitshift < 4; bitshift++)
  234. {
  235. for (register int i = 0; i < 16; i++)
  236. {
  237. register uint32 h = 0;
  238. register uint32 l = 0;
  239. #if defined(LSB_FIRST)
  240. if (i & 8)
  241. h |= PixelOdd;
  242. if (i & 4)
  243. h |= PixelOdd << 8;
  244. if (i & 2)
  245. h |= PixelOdd << 16;
  246. if (i & 1)
  247. h |= PixelOdd << 24;
  248. if (i & 8)
  249. l |= PixelOdd;
  250. if (i & 4)
  251. l |= PixelOdd << 8;
  252. if (i & 2)
  253. l |= PixelOdd << 16;
  254. if (i & 1)
  255. l |= PixelOdd << 24;
  256. #else
  257. if (i & 8)
  258. h |= (PixelOdd << 24);
  259. if (i & 4)
  260. h |= (PixelOdd << 16);
  261. if (i & 2)
  262. h |= (PixelOdd << 8);
  263. if (i & 1)
  264. h |= PixelOdd;
  265. if (i & 8)
  266. l |= (PixelOdd << 24);
  267. if (i & 4)
  268. l |= (PixelOdd << 16);
  269. if (i & 2)
  270. l |= (PixelOdd << 8);
  271. if (i & 1)
  272. l |= PixelOdd;
  273. #endif
  274. odd_high[bitshift][i] = h;
  275. odd_low[bitshift][i] = l;
  276. h = l = 0;
  277. #if defined(LSB_FIRST)
  278. if (i & 8)
  279. h |= PixelEven;
  280. if (i & 4)
  281. h |= PixelEven << 8;
  282. if (i & 2)
  283. h |= PixelEven << 16;
  284. if (i & 1)
  285. h |= PixelEven << 24;
  286. if (i & 8)
  287. l |= PixelEven;
  288. if (i & 4)
  289. l |= PixelEven << 8;
  290. if (i & 2)
  291. l |= PixelEven << 16;
  292. if (i & 1)
  293. l |= PixelEven << 24;
  294. #else
  295. if (i & 8)
  296. h |= (PixelEven << 24);
  297. if (i & 4)
  298. h |= (PixelEven << 16);
  299. if (i & 2)
  300. h |= (PixelEven << 8);
  301. if (i & 1)
  302. h |= PixelEven;
  303. if (i & 8)
  304. l |= (PixelEven << 24);
  305. if (i & 4)
  306. l |= (PixelEven << 16);
  307. if (i & 2)
  308. l |= (PixelEven << 8);
  309. if (i & 1)
  310. l |= PixelEven;
  311. #endif
  312. even_high[bitshift][i] = h;
  313. even_low[bitshift][i] = l;
  314. }
  315. PixelEven <<= 2;
  316. PixelOdd <<= 2;
  317. }
  318. GFX.RealPitch = GFX.Pitch2 = GFX.Pitch;
  319. GFX.ZPitch = GFX.Pitch;
  320. #ifndef FOREVER_16_BIT
  321. if (Settings.SixteenBit)
  322. #endif
  323. GFX.ZPitch >>= 1;
  324. GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
  325. GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
  326. //GFX.InfoStringTimeout = 0;
  327. //GFX.InfoString = NULL;
  328. PPU.BG_Forced = 0;
  329. IPPU.OBJChanged = TRUE;
  330. #ifndef FOREVER_16_BIT
  331. if (Settings.Transparency)
  332. Settings.SixteenBit = TRUE;
  333. #endif
  334. IPPU.DirectColourMapsNeedRebuild = TRUE;
  335. GFX.PixSize = 1;
  336. #ifndef FOREVER_16_BIT
  337. if (Settings.SixteenBit)
  338. {
  339. #endif
  340. DrawTilePtr = DrawTile16;
  341. DrawClippedTilePtr = DrawClippedTile16;
  342. DrawLargePixelPtr = DrawLargePixel16;
  343. if (Settings.SupportHiRes)
  344. {
  345. DrawHiResTilePtr= DrawTile16;
  346. DrawHiResClippedTilePtr = DrawClippedTile16;
  347. }
  348. else
  349. {
  350. DrawHiResTilePtr= DrawTile16HalfWidth;
  351. DrawHiResClippedTilePtr = DrawClippedTile16HalfWidth;
  352. }
  353. GFX.PPL = GFX.Pitch >> 1;
  354. GFX.PPLx2 = GFX.Pitch;
  355. #ifndef FOREVER_16_BIT
  356. }
  357. else
  358. {
  359. DrawTilePtr = DrawTile;
  360. DrawClippedTilePtr = DrawClippedTile;
  361. DrawLargePixelPtr = DrawLargePixel;
  362. if (Settings.SupportHiRes)
  363. {
  364. DrawHiResTilePtr= DrawTile;
  365. DrawHiResClippedTilePtr = DrawClippedTile;
  366. }
  367. else
  368. {
  369. DrawHiResTilePtr= DrawTileHalfWidth;
  370. DrawHiResClippedTilePtr = DrawClippedTileHalfWidth;
  371. }
  372. GFX.PPL = GFX.Pitch;
  373. GFX.PPLx2 = GFX.Pitch * 2;
  374. }
  375. #endif
  376. S9xFixColourBrightness ();
  377. #ifndef FOREVER_16_BIT
  378. if (Settings.SixteenBit)
  379. {
  380. #endif
  381. if (!(GFX.X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
  382. return (FALSE);
  383. if (!(GFX.ZERO_OR_X2 = (uint16 *) malloc (sizeof (uint16) * 0x10000)) ||
  384. !(GFX.ZERO = (uint16 *) malloc (sizeof (uint16) * 0x10000)))
  385. {
  386. if (GFX.ZERO_OR_X2)
  387. {
  388. free ((char *) GFX.ZERO_OR_X2);
  389. GFX.ZERO_OR_X2 = NULL;
  390. }
  391. if (GFX.X2)
  392. {
  393. free ((char *) GFX.X2);
  394. GFX.X2 = NULL;
  395. }
  396. return (FALSE);
  397. }
  398. uint32 r, g, b;
  399. // Build a lookup table that multiplies a packed RGB value by 2 with
  400. // saturation.
  401. for (r = 0; r <= MAX_RED; r++)
  402. {
  403. uint32 r2 = r << 1;
  404. if (r2 > MAX_RED)
  405. r2 = MAX_RED;
  406. for (g = 0; g <= MAX_GREEN; g++)
  407. {
  408. uint32 g2 = g << 1;
  409. if (g2 > MAX_GREEN)
  410. g2 = MAX_GREEN;
  411. for (b = 0; b <= MAX_BLUE; b++)
  412. {
  413. uint32 b2 = b << 1;
  414. if (b2 > MAX_BLUE)
  415. b2 = MAX_BLUE;
  416. GFX.X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
  417. GFX.X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
  418. }
  419. }
  420. }
  421. ZeroMemory (GFX.ZERO, 0x10000 * sizeof (uint16));
  422. ZeroMemory (GFX.ZERO_OR_X2, 0x10000 * sizeof (uint16));
  423. // Build a lookup table that if the top bit of the color value is zero
  424. // then the value is zero, otherwise multiply the value by 2. Used by
  425. // the color subtraction code.
  426. #if defined(OLD_COLOUR_BLENDING)
  427. for (r = 0; r <= MAX_RED; r++)
  428. {
  429. uint32 r2 = r;
  430. if ((r2 & 0x10) == 0)
  431. r2 = 0;
  432. else
  433. r2 = (r2 << 1) & MAX_RED;
  434. for (g = 0; g <= MAX_GREEN; g++)
  435. {
  436. uint32 g2 = g;
  437. if ((g2 & GREEN_HI_BIT) == 0)
  438. g2 = 0;
  439. else
  440. g2 = (g2 << 1) & MAX_GREEN;
  441. for (b = 0; b <= MAX_BLUE; b++)
  442. {
  443. uint32 b2 = b;
  444. if ((b2 & 0x10) == 0)
  445. b2 = 0;
  446. else
  447. b2 = (b2 << 1) & MAX_BLUE;
  448. GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
  449. GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
  450. }
  451. }
  452. }
  453. #else
  454. for (r = 0; r <= MAX_RED; r++)
  455. {
  456. uint32 r2 = r;
  457. if ((r2 & 0x10) == 0)
  458. r2 = 0;
  459. else
  460. r2 = (r2 << 1) & MAX_RED;
  461. if (r2 == 0)
  462. r2 = 1;
  463. for (g = 0; g <= MAX_GREEN; g++)
  464. {
  465. uint32 g2 = g;
  466. if ((g2 & GREEN_HI_BIT) == 0)
  467. g2 = 0;
  468. else
  469. g2 = (g2 << 1) & MAX_GREEN;
  470. if (g2 == 0)
  471. g2 = 1;
  472. for (b = 0; b <= MAX_BLUE; b++)
  473. {
  474. uint32 b2 = b;
  475. if ((b2 & 0x10) == 0)
  476. b2 = 0;
  477. else
  478. b2 = (b2 << 1) & MAX_BLUE;
  479. if (b2 == 0)
  480. b2 = 1;
  481. GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
  482. GFX.ZERO_OR_X2 [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
  483. }
  484. }
  485. }
  486. #endif
  487. // Build a lookup table that if the top bit of the color value is zero
  488. // then the value is zero, otherwise its just the value.
  489. for (r = 0; r <= MAX_RED; r++)
  490. {
  491. uint32 r2 = r;
  492. if ((r2 & 0x10) == 0)
  493. r2 = 0;
  494. else
  495. r2 &= ~0x10;
  496. for (g = 0; g <= MAX_GREEN; g++)
  497. {
  498. uint32 g2 = g;
  499. if ((g2 & GREEN_HI_BIT) == 0)
  500. g2 = 0;
  501. else
  502. g2 &= ~GREEN_HI_BIT;
  503. for (b = 0; b <= MAX_BLUE; b++)
  504. {
  505. uint32 b2 = b;
  506. if ((b2 & 0x10) == 0)
  507. b2 = 0;
  508. else
  509. b2 &= ~0x10;
  510. GFX.ZERO [BUILD_PIXEL2 (r, g, b)] = BUILD_PIXEL2 (r2, g2, b2);
  511. GFX.ZERO [BUILD_PIXEL2 (r, g, b) & ~ALPHA_BITS_MASK] = BUILD_PIXEL2 (r2, g2, b2);
  512. }
  513. }
  514. }
  515. #ifndef FOREVER_16_BIT
  516. }
  517. else
  518. {
  519. GFX.X2 = NULL;
  520. GFX.ZERO_OR_X2 = NULL;
  521. GFX.ZERO = NULL;
  522. }
  523. #endif
  524. return (TRUE);
  525. }
  526. void S9xGraphicsDeinit (void)
  527. {
  528. // Free any memory allocated in S9xGraphicsInit
  529. if (GFX.X2)
  530. {
  531. free ((char *) GFX.X2);
  532. GFX.X2 = NULL;
  533. }
  534. if (GFX.ZERO_OR_X2)
  535. {
  536. free ((char *) GFX.ZERO_OR_X2);
  537. GFX.ZERO_OR_X2 = NULL;
  538. }
  539. if (GFX.ZERO)
  540. {
  541. free ((char *) GFX.ZERO);
  542. GFX.ZERO = NULL;
  543. }
  544. }
  545. void S9xBuildDirectColourMaps ()
  546. {
  547. for (uint32 p = 0; p < 8; p++)
  548. {
  549. for (uint32 c = 0; c < 256; c++)
  550. {
  551. // XXX: Brightness
  552. DirectColourMaps [p][c] = BUILD_PIXEL (((c & 7) << 2) | ((p & 1) << 1),
  553. ((c & 0x38) >> 1) | (p & 2),
  554. ((c & 0xc0) >> 3) | (p & 4));
  555. }
  556. }
  557. IPPU.DirectColourMapsNeedRebuild = FALSE;
  558. }
  559. void S9xStartScreenRefresh ()
  560. {
  561. if (GFX.InfoStringTimeout > 0 && --GFX.InfoStringTimeout == 0)
  562. GFX.InfoString = NULL;
  563. if (IPPU.RenderThisFrame)
  564. {
  565. if (!S9xInitUpdate ())
  566. {
  567. IPPU.RenderThisFrame = FALSE;
  568. return;
  569. }
  570. IPPU.RenderedFramesCount++;
  571. IPPU.PreviousLine = IPPU.CurrentLine = 0;
  572. IPPU.MaxBrightness = PPU.Brightness;
  573. IPPU.LatchedBlanking = PPU.ForcedBlanking;
  574. if(PPU.BGMode == 5 || PPU.BGMode == 6)
  575. IPPU.Interlace = (Memory.FillRAM[0x2133] & 1);
  576. if (Settings.SupportHiRes && (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.Interlace))
  577. {
  578. IPPU.RenderedScreenWidth = 512;
  579. IPPU.DoubleWidthPixels = TRUE;
  580. IPPU.HalfWidthPixels = FALSE;
  581. if (IPPU.Interlace)
  582. {
  583. IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1;
  584. IPPU.DoubleHeightPixels = TRUE;
  585. GFX.Pitch2 = GFX.RealPitch;
  586. GFX.Pitch = GFX.RealPitch * 2;
  587. #ifndef FOREVER_16_BIT
  588. if (Settings.SixteenBit)
  589. #endif
  590. GFX.PPL = GFX.PPLx2 = GFX.RealPitch;
  591. #ifndef FOREVER_16_BIT
  592. else
  593. GFX.PPL = GFX.PPLx2 = GFX.RealPitch << 1;
  594. #endif
  595. }
  596. else
  597. {
  598. IPPU.RenderedScreenHeight = PPU.ScreenHeight;
  599. GFX.Pitch2 = GFX.Pitch = GFX.RealPitch;
  600. IPPU.DoubleHeightPixels = FALSE;
  601. #ifndef FOREVER_16_BIT
  602. if (Settings.SixteenBit)
  603. #endif
  604. GFX.PPL = GFX.Pitch >> 1;
  605. #ifndef FOREVER_16_BIT
  606. else
  607. GFX.PPL = GFX.Pitch;
  608. #endif
  609. GFX.PPLx2 = GFX.PPL << 1;
  610. }
  611. }
  612. else if (!Settings.SupportHiRes && (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.Interlace))
  613. {
  614. IPPU.RenderedScreenWidth = 256;
  615. IPPU.DoubleWidthPixels = FALSE;
  616. // Secret of Mana displays menus with mode 5.
  617. // Make them readable.
  618. IPPU.HalfWidthPixels = TRUE;
  619. }
  620. else
  621. {
  622. IPPU.RenderedScreenWidth = 256;
  623. IPPU.RenderedScreenHeight = PPU.ScreenHeight;
  624. IPPU.DoubleWidthPixels = FALSE;
  625. IPPU.HalfWidthPixels = FALSE;
  626. IPPU.DoubleHeightPixels = FALSE;
  627. {
  628. GFX.Pitch2 = GFX.Pitch = GFX.RealPitch;
  629. GFX.PPL = GFX.PPLx2 >> 1;
  630. GFX.ZPitch = GFX.RealPitch;
  631. #ifndef FOREVER_16_BIT
  632. if (Settings.SixteenBit)
  633. #endif
  634. GFX.ZPitch >>= 1;
  635. }
  636. }
  637. PPU.RecomputeClipWindows = TRUE;
  638. GFX.DepthDelta = GFX.SubZBuffer - GFX.ZBuffer;
  639. GFX.Delta = (GFX.SubScreen - GFX.Screen) >> 1;
  640. }
  641. if (++IPPU.FrameCount % Memory.ROMFramesPerSecond == 0)
  642. {
  643. IPPU.DisplayedRenderedFrameCount = IPPU.RenderedFramesCount;
  644. IPPU.RenderedFramesCount = 0;
  645. IPPU.FrameCount = 0;
  646. }
  647. }
  648. void RenderLine (uint8 C)
  649. {
  650. if (IPPU.RenderThisFrame)
  651. {
  652. LineData[C].BG[0].VOffset = PPU.BG[0].VOffset + 1;
  653. LineData[C].BG[0].HOffset = PPU.BG[0].HOffset;
  654. LineData[C].BG[1].VOffset = PPU.BG[1].VOffset + 1;
  655. LineData[C].BG[1].HOffset = PPU.BG[1].HOffset;
  656. if (PPU.BGMode == 7)
  657. {
  658. struct SLineMatrixData *p = &LineMatrixData [C];
  659. p->MatrixA = PPU.MatrixA;
  660. p->MatrixB = PPU.MatrixB;
  661. p->MatrixC = PPU.MatrixC;
  662. p->MatrixD = PPU.MatrixD;
  663. p->CentreX = PPU.CentreX;
  664. p->CentreY = PPU.CentreY;
  665. }
  666. else
  667. {
  668. if (Settings.StarfoxHack && PPU.BG[2].VOffset == 0 &&
  669. PPU.BG[2].HOffset == 0xe000)
  670. {
  671. LineData[C].BG[2].VOffset = 0xe1;
  672. LineData[C].BG[2].HOffset = 0;
  673. }
  674. else
  675. {
  676. LineData[C].BG[2].VOffset = PPU.BG[2].VOffset + 1;
  677. LineData[C].BG[2].HOffset = PPU.BG[2].HOffset;
  678. LineData[C].BG[3].VOffset = PPU.BG[3].VOffset + 1;
  679. LineData[C].BG[3].HOffset = PPU.BG[3].HOffset;
  680. }
  681. }
  682. IPPU.CurrentLine = C + 1;
  683. } else {
  684. /* if we're not rendering this frame, we still need to update this */
  685. // XXX: Check ForceBlank? Or anything else?
  686. if(IPPU.OBJChanged) S9xSetupOBJ();
  687. PPU.RangeTimeOver |= GFX.OBJLines[C].RTOFlags;
  688. }
  689. }
  690. void S9xEndScreenRefresh ()
  691. {
  692. IPPU.HDMAStarted = FALSE;
  693. if (IPPU.RenderThisFrame)
  694. {
  695. FLUSH_REDRAW ();
  696. if (IPPU.ColorsChanged)
  697. {
  698. uint32 saved = PPU.CGDATA[0];
  699. #ifndef FOREVER_16_BIT
  700. if (!Settings.SixteenBit)
  701. {
  702. // Hack for Super Mario World - to get its sky blue
  703. // (It uses Fixed colour addition on the backdrop colour)
  704. if (!(Memory.FillRAM [0x2131] & 0x80) && (Memory.FillRAM[0x2131] & 0x20) &&
  705. (PPU.FixedColourRed || PPU.FixedColourGreen || PPU.FixedColourBlue))
  706. {
  707. PPU.CGDATA[0] = PPU.FixedColourRed | (PPU.FixedColourGreen << 5) |
  708. (PPU.FixedColourBlue << 10);
  709. }
  710. }
  711. #endif
  712. IPPU.ColorsChanged = FALSE;
  713. PPU.CGDATA[0] = saved;
  714. }
  715. GFX.Pitch = GFX.Pitch2 = GFX.RealPitch;
  716. GFX.PPL = GFX.PPLx2 >> 1;
  717. #if 0
  718. //take screenshot here.
  719. if(Settings.TakeScreenshot)
  720. {
  721. S9xDoScreenshot(IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight);
  722. cprintf("%s:%d\n", __FILE__, __LINE__);
  723. }
  724. if (Settings.DisplayFrameRate)
  725. {
  726. S9xDisplayFrameRate ();
  727. cprintf("%s:%d\n", __FILE__, __LINE__);
  728. }
  729. if (GFX.InfoString)
  730. {
  731. S9xDisplayString (GFX.InfoString);
  732. cprintf("%s:%d\n", __FILE__, __LINE__);
  733. }
  734. #endif
  735. S9xDeinitUpdate (IPPU.RenderedScreenWidth, IPPU.RenderedScreenHeight,
  736. #ifndef FOREVER_16_BIT
  737. Settings.SixteenBit
  738. #else
  739. TRUE
  740. #endif
  741. );
  742. }
  743. S9xApplyCheats ();
  744. #ifdef DEBUGGER
  745. if (CPU.Flags & FRAME_ADVANCE_FLAG)
  746. {
  747. if (ICPU.FrameAdvanceCount)
  748. {
  749. ICPU.FrameAdvanceCount--;
  750. IPPU.RenderThisFrame = TRUE;
  751. IPPU.FrameSkip = 0;
  752. }
  753. else
  754. {
  755. CPU.Flags &= ~FRAME_ADVANCE_FLAG;
  756. CPU.Flags |= DEBUG_MODE_FLAG;
  757. }
  758. }
  759. #endif
  760. if (CPU.SRAMModified)
  761. {
  762. S9xAutoSaveSRAM ();
  763. CPU.SRAMModified = FALSE;
  764. /*if (!CPU.AutoSaveTimer)
  765. {
  766. if (!(CPU.AutoSaveTimer = Settings.AutoSaveDelay * Memory.ROMFramesPerSecond))
  767. CPU.SRAMModified = FALSE;
  768. }
  769. else
  770. {
  771. if (!--CPU.AutoSaveTimer)
  772. {
  773. S9xAutoSaveSRAM ();
  774. CPU.SRAMModified = FALSE;
  775. }
  776. }*/
  777. }
  778. }
  779. void S9xSetInfoString (const char *string)
  780. {
  781. GFX.InfoString = string;
  782. GFX.InfoStringTimeout = 120;
  783. }
  784. inline void SelectTileRenderer (bool8 normal)
  785. {
  786. if (normal)
  787. {
  788. if (IPPU.HalfWidthPixels)
  789. {
  790. DrawTilePtr = DrawTile16HalfWidth;
  791. DrawClippedTilePtr = DrawClippedTile16HalfWidth;
  792. DrawLargePixelPtr = DrawLargePixel16HalfWidth;
  793. }
  794. else
  795. {
  796. DrawTilePtr = DrawTile16;
  797. DrawClippedTilePtr = DrawClippedTile16;
  798. DrawLargePixelPtr = DrawLargePixel16;
  799. }
  800. }
  801. else
  802. {
  803. switch (GFX.r2131 & 0xC0)
  804. {
  805. case 0x00:
  806. DrawTilePtr = DrawTile16Add;
  807. DrawClippedTilePtr = DrawClippedTile16Add;
  808. DrawLargePixelPtr = DrawLargePixel16Add;
  809. break;
  810. case 0x40:
  811. if (GFX.r2130 & 2)
  812. {
  813. DrawTilePtr = DrawTile16Add1_2;
  814. DrawClippedTilePtr = DrawClippedTile16Add1_2;
  815. }
  816. else
  817. {
  818. // Fixed colour addition
  819. DrawTilePtr = DrawTile16FixedAdd1_2;
  820. DrawClippedTilePtr = DrawClippedTile16FixedAdd1_2;
  821. }
  822. DrawLargePixelPtr = DrawLargePixel16Add1_2;
  823. break;
  824. case 0x80:
  825. DrawTilePtr = DrawTile16Sub;
  826. DrawClippedTilePtr = DrawClippedTile16Sub;
  827. DrawLargePixelPtr = DrawLargePixel16Sub;
  828. break;
  829. case 0xC0:
  830. if (GFX.r2130 & 2)
  831. {
  832. DrawTilePtr = DrawTile16Sub1_2;
  833. DrawClippedTilePtr = DrawClippedTile16Sub1_2;
  834. }
  835. else
  836. {
  837. // Fixed colour substraction
  838. DrawTilePtr = DrawTile16FixedSub1_2;
  839. DrawClippedTilePtr = DrawClippedTile16FixedSub1_2;
  840. }
  841. DrawLargePixelPtr = DrawLargePixel16Sub1_2;
  842. break;
  843. }
  844. }
  845. }
  846. void S9xSetupOBJ ()
  847. {
  848. #ifdef MK_DEBUG_RTO
  849. if(Settings.BGLayering) fprintf(stderr, "Entering SetupOBJS()\n");
  850. #endif
  851. int SmallWidth, SmallHeight;
  852. int LargeWidth, LargeHeight;
  853. switch (PPU.OBJSizeSelect)
  854. {
  855. case 0:
  856. SmallWidth = SmallHeight = 8;
  857. LargeWidth = LargeHeight = 16;
  858. break;
  859. case 1:
  860. SmallWidth = SmallHeight = 8;
  861. LargeWidth = LargeHeight = 32;
  862. break;
  863. case 2:
  864. SmallWidth = SmallHeight = 8;
  865. LargeWidth = LargeHeight = 64;
  866. break;
  867. case 3:
  868. SmallWidth = SmallHeight = 16;
  869. LargeWidth = LargeHeight = 32;
  870. break;
  871. case 4:
  872. SmallWidth = SmallHeight = 16;
  873. LargeWidth = LargeHeight = 64;
  874. break;
  875. default:
  876. case 5:
  877. SmallWidth = SmallHeight = 32;
  878. LargeWidth = LargeHeight = 64;
  879. break;
  880. case 6:
  881. SmallWidth = 16; SmallHeight = 32;
  882. LargeWidth = 32; LargeHeight = 64;
  883. break;
  884. case 7:
  885. SmallWidth = 16; SmallHeight = 32;
  886. LargeWidth = LargeHeight = 32;
  887. break;
  888. }
  889. if(IPPU.InterlaceSprites)
  890. {
  891. SmallHeight>>=1; LargeHeight>>=1;
  892. }
  893. #ifdef MK_DEBUG_RTO
  894. if(Settings.BGLayering) fprintf(stderr, "Sizes are %dx%d and %dx%d\n", SmallWidth, SmallHeight, LargeWidth, LargeHeight);
  895. #endif
  896. /* OK, we have three cases here. Either there's no priority, priority is
  897. * normal FirstSprite, or priority is FirstSprite+Y. The first two are
  898. * easy, the last is somewhat more ... interesting. So we split them up. */
  899. int Height;
  900. uint8 S;
  901. #ifdef MK_DEBUG_RTO
  902. if(Settings.BGLayering) fprintf(stderr, "Priority rotation=%d, OAMAddr=%d -> ", PPU.OAMPriorityRotation, PPU.OAMAddr*2 | (PPU.OAMFlip&1));
  903. #endif
  904. if(!PPU.OAMPriorityRotation || !(PPU.OAMFlip&PPU.OAMAddr&1)){
  905. #ifdef MK_DEBUG_RTO
  906. if(Settings.BGLayering) fprintf(stderr, "normal FirstSprite = %02x\n", PPU.FirstSprite);
  907. #endif
  908. /* normal case */
  909. uint8 LineOBJ[SNES_HEIGHT_EXTENDED];
  910. memset(LineOBJ, 0, sizeof(LineOBJ));
  911. for(int i=0; i<SNES_HEIGHT_EXTENDED; i++){
  912. GFX.OBJLines[i].RTOFlags=0;
  913. GFX.OBJLines[i].Tiles=34;
  914. }
  915. uint8 FirstSprite=PPU.FirstSprite;
  916. S=FirstSprite;
  917. do {
  918. if(PPU.OBJ[S].Size){
  919. GFX.OBJWidths[S]=LargeWidth; Height=LargeHeight;
  920. } else {
  921. GFX.OBJWidths[S]=SmallWidth; Height=SmallHeight;
  922. }
  923. int HPos=PPU.OBJ[S].HPos; if(HPos==-256) HPos=256;
  924. if(HPos>-GFX.OBJWidths[S] && HPos<=256)
  925. {
  926. if(HPos<0){
  927. GFX.OBJVisibleTiles[S]=(GFX.OBJWidths[S]+HPos+7)>>3;
  928. } else if(HPos+GFX.OBJWidths[S]>=257){
  929. GFX.OBJVisibleTiles[S]=(257-HPos+7)>>3;
  930. } else {
  931. GFX.OBJVisibleTiles[S]=GFX.OBJWidths[S]>>3;
  932. }
  933. for(uint8 line=0, Y=(uint8)(PPU.OBJ[S].VPos&0xff); line<Height; Y++, line++){
  934. if(Y>=SNES_HEIGHT_EXTENDED) continue;
  935. if(LineOBJ[Y]>=32){
  936. GFX.OBJLines[Y].RTOFlags|=0x40;
  937. #ifdef MK_DEBUG_RTO
  938. if(Settings.BGLayering) fprintf(stderr, "%d: OBJ %02x ranged over\n", Y, S);
  939. #endif
  940. continue;
  941. }
  942. GFX.OBJLines[Y].Tiles-=GFX.OBJVisibleTiles[S];
  943. if(GFX.OBJLines[Y].Tiles<0) GFX.OBJLines[Y].RTOFlags|=0x80;
  944. GFX.OBJLines[Y].OBJ[LineOBJ[Y]].Sprite=S;
  945. if(PPU.OBJ[S].VFlip){
  946. // Yes, Width not Height. It so happens that the
  947. // sprites with H=2*W flip as two WxW sprites.
  948. GFX.OBJLines[Y].OBJ[LineOBJ[Y]].Line=line^(GFX.OBJWidths[S]-1);
  949. } else {
  950. GFX.OBJLines[Y].OBJ[LineOBJ[Y]].Line=line;
  951. }
  952. LineOBJ[Y]++;
  953. }
  954. }
  955. S=(S+1)&0x7F;
  956. } while(S!=FirstSprite);
  957. for (int Y = 0; Y < SNES_HEIGHT_EXTENDED; Y++) {
  958. if (LineOBJ[Y] < 32) // Add the sentinel
  959. GFX.OBJLines[Y].OBJ[LineOBJ[Y]].Sprite = -1;
  960. }
  961. for(int Y=1; Y<SNES_HEIGHT_EXTENDED; Y++){
  962. GFX.OBJLines[Y].RTOFlags |= GFX.OBJLines[Y-1].RTOFlags;
  963. }
  964. } else {
  965. /* evil FirstSprite+Y case */
  966. #ifdef MK_DEBUG_RTO
  967. if(Settings.BGLayering) fprintf(stderr, "FirstSprite+Y\n");
  968. #endif
  969. /* First, find out which sprites are on which lines */
  970. uint8 OBJOnLine[SNES_HEIGHT_EXTENDED][128];
  971. // memset(OBJOnLine, 0, sizeof(OBJOnLine));
  972. /* Hold on here, that's a lot of bytes to initialise at once!
  973. * So we only initialise them per line, as needed. [Neb]
  974. * Bonus: We can quickly avoid looping if a line has no OBJs.
  975. */
  976. bool8 AnyOBJOnLine[SNES_HEIGHT_EXTENDED];
  977. memset(AnyOBJOnLine, FALSE, sizeof(AnyOBJOnLine)); // better
  978. for(S=0; S<128; S++){
  979. if(PPU.OBJ[S].Size){
  980. GFX.OBJWidths[S]=LargeWidth; Height=LargeHeight;
  981. } else {
  982. GFX.OBJWidths[S]=SmallWidth; Height=SmallHeight;
  983. }
  984. int HPos=PPU.OBJ[S].HPos; if(HPos==-256) HPos=256;
  985. if(HPos>-GFX.OBJWidths[S] && HPos<=256)
  986. {
  987. if(HPos<0){
  988. GFX.OBJVisibleTiles[S]=(GFX.OBJWidths[S]+HPos+7)>>3;
  989. } else if(HPos+GFX.OBJWidths[S]>=257){
  990. GFX.OBJVisibleTiles[S]=(257-HPos+7)>>3;
  991. } else {
  992. GFX.OBJVisibleTiles[S]=GFX.OBJWidths[S]>>3;
  993. }
  994. for(uint8 line=0, Y=(uint8)(PPU.OBJ[S].VPos&0xff); line<Height; Y++, line++){
  995. if(Y>=SNES_HEIGHT_EXTENDED) continue;
  996. if (!AnyOBJOnLine[Y]) {
  997. memset(OBJOnLine[Y], 0, 128);
  998. AnyOBJOnLine[Y] = TRUE;
  999. }
  1000. if(PPU.OBJ[S].VFlip){
  1001. // Yes, Width not Height. It so happens that the
  1002. // sprites with H=2*W flip as two WxW sprites.
  1003. OBJOnLine[Y][S]=(line^(GFX.OBJWidths[S]-1)) | 0x80;
  1004. } else {
  1005. OBJOnLine[Y][S]=line | 0x80;
  1006. }
  1007. }
  1008. }
  1009. }
  1010. /* Now go through and pull out those OBJ that are actually visible. */
  1011. int j;
  1012. for(int Y=0; Y<SNES_HEIGHT_EXTENDED; Y++){
  1013. GFX.OBJLines[Y].RTOFlags=Y?0:GFX.OBJLines[Y-1].RTOFlags;
  1014. GFX.OBJLines[Y].Tiles=34;
  1015. j=0;
  1016. if (AnyOBJOnLine[Y]) {
  1017. uint8 FirstSprite=(PPU.FirstSprite+Y)&0x7F;
  1018. S=FirstSprite;
  1019. do {
  1020. if(OBJOnLine[Y][S]){
  1021. if(j>=32){
  1022. GFX.OBJLines[Y].RTOFlags|=0x40;
  1023. #ifdef MK_DEBUG_RTO
  1024. if(Settings.BGLayering) fprintf(stderr, "%d: OBJ %02x ranged over\n", Y, S);
  1025. #endif
  1026. break;
  1027. }
  1028. GFX.OBJLines[Y].Tiles-=GFX.OBJVisibleTiles[S];
  1029. if(GFX.OBJLines[Y].Tiles<0) GFX.OBJLines[Y].RTOFlags|=0x80;
  1030. GFX.OBJLines[Y].OBJ[j].Sprite=S;
  1031. GFX.OBJLines[Y].OBJ[j++].Line=OBJOnLine[Y][S]&~0x80;
  1032. }
  1033. S=(S+1)&0x7F;
  1034. } while(S!=FirstSprite);
  1035. }
  1036. if(j<32) GFX.OBJLines[Y].OBJ[j].Sprite=-1;
  1037. }
  1038. }
  1039. #ifdef MK_DEBUG_RTO
  1040. if(Settings.BGLayering) {
  1041. fprintf(stderr, "Sprites per line:\n");
  1042. for(int xxx=0; xxx<SNES_HEIGHT_EXTENDED; xxx++){
  1043. fprintf(stderr, "Line %d: RTO=%02x Tiles=%d", xxx, GFX.OBJLines[xxx].RTOFlags, 34-GFX.OBJLines[xxx].Tiles);
  1044. for(int j=0; j<32 && GFX.OBJLines[xxx].OBJ[j].Sprite>=0; j++){
  1045. fprintf(stderr, " %02x.%d", GFX.OBJLines[xxx].OBJ[j].Sprite, GFX.OBJLines[xxx].OBJ[j].Line);
  1046. }
  1047. fprintf(stderr, "\n");
  1048. }
  1049. fprintf(stderr, "Exiting SetupObj()\n");
  1050. }
  1051. #endif
  1052. IPPU.OBJChanged = FALSE;
  1053. }
  1054. static void DrawOBJS (bool8 OnMain = FALSE, uint8 D = 0)
  1055. {
  1056. #ifdef ACCUMULATE_JOYPAD
  1057. /*
  1058. * This call allows NDSSFC to synchronise the DS controller more often.
  1059. * If porting a later version of Snes9x into NDSSFC, it is essential to
  1060. * preserve it.
  1061. */
  1062. NDSSFCAccumulateJoypad ();
  1063. #endif
  1064. #ifdef MK_DEBUG_RTO
  1065. if(Settings.BGLayering) fprintf(stderr, "Entering DrawOBJS() for %d-%d\n", GFX.StartY, GFX.EndY);
  1066. #endif
  1067. CHECK_SOUND();
  1068. BG.BitShift = 4;
  1069. BG.TileShift = 5;
  1070. BG.TileAddress = PPU.OBJNameBase;
  1071. BG.StartPalette = 128;
  1072. BG.PaletteShift = 4;
  1073. BG.PaletteMask = 7;
  1074. BG.Buffer = IPPU.TileCache [TILE_4BIT];
  1075. BG.Buffered = IPPU.TileCached [TILE_4BIT];
  1076. BG.NameSelect = PPU.OBJNameSelect;
  1077. BG.DirectColourMode = FALSE;
  1078. GFX.PixSize = 1;
  1079. struct {
  1080. uint16 Pos;
  1081. bool8 Value;
  1082. } Windows[7];
  1083. int clipcount = GFX.pCurrentClip->Count [4];
  1084. if (!clipcount){
  1085. Windows[0].Pos=0;
  1086. Windows[0].Value=TRUE;
  1087. Windows[1].Pos=256;
  1088. Windows[1].Value=FALSE;
  1089. Windows[2].Pos=1000;
  1090. Windows[2].Value=FALSE;
  1091. } else {
  1092. Windows[0].Pos=1000;
  1093. Windows[0].Value=FALSE;
  1094. for(int clip=0, i=1; clip<clipcount; clip++){
  1095. if(GFX.pCurrentClip->Right[clip][4]<=GFX.pCurrentClip->Left[clip][4]) continue;
  1096. int j;
  1097. for(j=0; j<i && Windows[j].Pos<GFX.pCurrentClip->Left[clip][4]; j++);
  1098. if(j<i && Windows[j].Pos==GFX.pCurrentClip->Left[clip][4]){
  1099. Windows[j].Value = TRUE;
  1100. } else {
  1101. // memmove required: Overlapping addresses [Neb]
  1102. if(j<i) memmove(&Windows[j+1], &Windows[j], sizeof(Windows[0])*(i-j));
  1103. Windows[j].Pos = GFX.pCurrentClip->Left[clip][4];
  1104. Windows[j].Value = TRUE;
  1105. i++;
  1106. }
  1107. for(j=0; j<i && Windows[j].Pos<GFX.pCurrentClip->Right[clip][4]; j++);
  1108. if(j>=i || Windows[j].Pos!=GFX.pCurrentClip->Right[clip][4]){
  1109. // memmove required: Overlapping addresses [Neb]
  1110. if(j<i) memmove(&Windows[j+1], &Windows[j], sizeof(Windows[0])*(i-j));
  1111. Windows[j].Pos = GFX.pCurrentClip->Right[clip][4];
  1112. Windows[j].Value = FALSE;
  1113. i++;
  1114. }
  1115. }
  1116. }
  1117. #ifdef MK_DEBUG_RTO
  1118. if(Settings.BGLayering) {
  1119. fprintf(stderr, "Windows:\n");
  1120. for(int xxx=0; xxx<6; xxx++){ fprintf(stderr, "%d: %d = %d\n", xxx, Windows[xxx].Pos, Windows[xxx].Value); }
  1121. }
  1122. #endif
  1123. if (Settings.SupportHiRes)
  1124. {
  1125. if (PPU.BGMode == 5 || PPU.BGMode == 6)
  1126. {
  1127. // Bah, OnMain is never used except to determine if calling
  1128. // SelectTileRenderer is necessary. So let's hack it to false here
  1129. // to stop SelectTileRenderer from being called when it causes
  1130. // problems.
  1131. OnMain = FALSE;
  1132. GFX.PixSize = 2;
  1133. if (IPPU.DoubleHeightPixels)
  1134. {
  1135. #ifndef FOREVER_16_BIT
  1136. if (Settings.SixteenBit)
  1137. {
  1138. #endif
  1139. DrawTilePtr = DrawTile16x2x2;
  1140. DrawClippedTilePtr = DrawClippedTile16x2x2;
  1141. #ifndef FOREVER_16_BIT
  1142. }
  1143. else
  1144. {
  1145. DrawTilePtr = DrawTilex2x2;
  1146. DrawClippedTilePtr = DrawClippedTilex2x2;
  1147. }
  1148. #endif
  1149. }
  1150. else
  1151. {
  1152. #ifndef FOREVER_16_BIT
  1153. if (Settings.SixteenBit)
  1154. {
  1155. #endif
  1156. DrawTilePtr = DrawTile16x2;
  1157. DrawClippedTilePtr = DrawClippedTile16x2;
  1158. #ifndef FOREVER_16_BIT
  1159. }
  1160. else
  1161. {
  1162. DrawTilePtr = DrawTilex2;
  1163. DrawClippedTilePtr = DrawClippedTilex2;
  1164. }
  1165. #endif
  1166. }
  1167. }
  1168. else
  1169. {
  1170. #ifndef FOREVER_16_BIT
  1171. if (Settings.SixteenBit)
  1172. {
  1173. #endif
  1174. DrawTilePtr = DrawTile16;
  1175. DrawClippedTilePtr = DrawClippedTile16;
  1176. #ifndef FOREVER_16_BIT
  1177. }
  1178. else
  1179. {
  1180. DrawTilePtr = DrawTile;
  1181. DrawClippedTilePtr = DrawClippedTile;
  1182. }
  1183. #endif
  1184. }
  1185. }
  1186. else // if (!Settings.SupportHiRes)
  1187. {
  1188. if (PPU.BGMode == 5 || PPU.BGMode == 6)
  1189. {
  1190. // Bah, OnMain is never used except to determine if calling
  1191. // SelectTileRenderer is necessary. So let's hack it to false here
  1192. // to stop SelectTileRenderer from being called when it causes
  1193. // problems.
  1194. OnMain = FALSE;
  1195. }
  1196. #ifndef FOREVER_16_BIT
  1197. if (Settings.SixteenBit)
  1198. {
  1199. #endif
  1200. DrawTilePtr = DrawTile16;
  1201. DrawClippedTilePtr = DrawClippedTile16;
  1202. #ifndef FOREVER_16_BIT
  1203. }
  1204. else
  1205. {
  1206. DrawTilePtr = DrawTile;
  1207. DrawClippedTilePtr = DrawClippedTile;
  1208. }
  1209. #endif
  1210. }
  1211. GFX.Z1 = D + 2;
  1212. for(uint32 Y=GFX.StartY, Offset=Y*GFX.PPL; Y<=GFX.EndY; Y++, Offset+=GFX.PPL){
  1213. #ifdef MK_DEBUG_RTO
  1214. bool8 Flag=0;
  1215. #endif
  1216. int I = 0;
  1217. #ifdef MK_DISABLE_TIME_OVER
  1218. int tiles=0;
  1219. #else
  1220. int tiles=GFX.OBJLines[Y].Tiles;
  1221. #endif
  1222. for (int S = GFX.OBJLines[Y].OBJ[I].Sprite; S >= 0 && I<32; S = GFX.OBJLines[Y].OBJ[++I].Sprite)
  1223. {
  1224. tiles+=GFX.OBJVisibleTiles[S];
  1225. if(tiles<=0){
  1226. #ifdef MK_DEBUG_RTO
  1227. if(Settings.BGLayering) {
  1228. if(!Flag){ Flag=1; fprintf(stderr, "Line %d:", Y); }
  1229. fprintf(stderr, " [%02x]", S);
  1230. }
  1231. #endif
  1232. continue;
  1233. }
  1234. #ifdef MK_DEBUG_RTO
  1235. if(Settings.BGLayering) {
  1236. if(!Flag){ Flag=1; fprintf(stderr, "Line %d:", Y); }
  1237. fprintf(stderr, " %02x", S);
  1238. }
  1239. #endif
  1240. if (OnMain && SUB_OR_ADD(4))
  1241. {
  1242. SelectTileRenderer (!GFX.Pseudo && PPU.OBJ [S].Palette < 4);
  1243. }
  1244. int BaseTile = (((GFX.OBJLines[Y].OBJ[I].Line<<1) + (PPU.OBJ[S].Name&0xf0))&0xf0) | (PPU.OBJ[S].Name&0x100) | (PPU.OBJ[S].Palette << 10);
  1245. int TileX = PPU.OBJ[S].Name&0x0f;
  1246. int TileLine = (GFX.OBJLines[Y].OBJ[I].Line&7)*8;
  1247. int TileInc = 1;
  1248. if (PPU.OBJ[S].HFlip)
  1249. {
  1250. TileX = (TileX + (GFX.OBJWidths[S] >> 3) - 1) & 0x0f;
  1251. BaseTile |= H_FLIP;
  1252. TileInc = -1;
  1253. }
  1254. GFX.Z2 = (PPU.OBJ[S].Priority + 1) * 4 + D;
  1255. bool8 WinStat=TRUE;
  1256. int WinIdx=0, NextPos=-1000;
  1257. int X=PPU.OBJ[S].HPos; if(X==-256) X=256;
  1258. for(int t=tiles, O=Offset+X*GFX.PixSize; X<=256 && X<PPU.OBJ[S].HPos+GFX.OBJWidths[S]; TileX=(TileX+TileInc)&0x0f, X+=8, O+=8*GFX.PixSize){
  1259. #ifdef MK_DEBUG_RTO
  1260. if(Settings.BGLayering) {
  1261. if(X<-7) continue;
  1262. if((t-1)<0) fprintf(stderr, "-[%d]", 35-t);
  1263. else fprintf(stderr, "-%d", 35-t);
  1264. }
  1265. #endif
  1266. if(X<-7 || --t<0 || X==256) continue;
  1267. if(X>=NextPos){
  1268. for(; WinIdx<7 && Windows[WinIdx].Pos<=X; WinIdx++);
  1269. if(WinIdx==0) WinStat=FALSE;
  1270. else WinStat=Windows[WinIdx-1].Value;
  1271. NextPos=(WinIdx<7)?Windows[WinIdx].Pos:1000;
  1272. }
  1273. if(X+8<NextPos){
  1274. if(WinStat) (*DrawTilePtr) (BaseTile|TileX, O, TileLine, 1);
  1275. } else {
  1276. int x=X;
  1277. while(x<X+8){
  1278. if(WinStat) (*DrawClippedTilePtr) (BaseTile|TileX, O, x-X, NextPos-x, TileLine, 1);
  1279. x=NextPos;
  1280. for(; WinIdx<7 && Windows[WinIdx].Pos<=x; WinIdx++);
  1281. if(WinIdx==0) WinStat=FALSE;
  1282. else WinStat=Windows[WinIdx-1].Value;
  1283. NextPos=(WinIdx<7)?Windows[WinIdx].Pos:1000;
  1284. if(NextPos>X+8) NextPos=X+8;
  1285. }
  1286. }
  1287. }
  1288. }
  1289. #ifdef MK_DEBUG_RTO
  1290. if(Settings.BGLayering) if(Flag) fprintf(stderr, "\n");
  1291. #endif
  1292. }
  1293. #ifdef MK_DEBUG_RTO
  1294. if(Settings.BGLayering) fprintf(stderr, "Exiting DrawOBJS() for %d-%d\n", GFX.StartY, GFX.EndY);
  1295. #endif
  1296. }
  1297. static void DrawBackgroundMosaic (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
  1298. {
  1299. CHECK_SOUND();
  1300. uint32 Tile;
  1301. uint16 *SC0;
  1302. uint16 *SC1;
  1303. uint16 *SC2;
  1304. uint16 *SC3;
  1305. uint8 depths [2] = {Z1, Z2};
  1306. if (BGMode == 0)
  1307. BG.StartPalette = bg << 5;
  1308. else
  1309. BG.StartPalette = 0;
  1310. SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
  1311. if (PPU.BG[bg].SCSize & 1)
  1312. SC1 = SC0 + 1024;
  1313. else
  1314. SC1 = SC0;
  1315. if(((uint8*)SC1-Memory.VRAM)>=0x10000)
  1316. SC1-=0x08000;
  1317. if (PPU.BG[bg].SCSize & 2)
  1318. SC2 = SC1 + 1024;
  1319. else
  1320. SC2 = SC0;
  1321. if(((uint8*)SC2-Memory.VRAM)>=0x10000)
  1322. SC2-=0x08000;
  1323. if (PPU.BG[bg].SCSize & 1)
  1324. SC3 = SC2 + 1024;
  1325. else
  1326. SC3 = SC2;
  1327. if(((uint8*)SC3-Memory.VRAM)>=0x10000)
  1328. SC3-=0x08000;
  1329. uint32 Lines;
  1330. uint32 OffsetMask;
  1331. uint32 OffsetShift;
  1332. if (BG.TileSize == 16)
  1333. {
  1334. OffsetMask = 0x3ff;
  1335. OffsetShift = 4;
  1336. }
  1337. else
  1338. {
  1339. OffsetMask = 0x1ff;
  1340. OffsetShift = 3;
  1341. }
  1342. int m5 = (BGMode == 5 || BGMode == 6) ? 1 : 0;
  1343. for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
  1344. {
  1345. uint32 VOffset = LineData [Y].BG[bg].VOffset;
  1346. uint32 HOffset = LineData [Y].BG[bg].HOffset;
  1347. uint32 MosaicOffset = Y % PPU.Mosaic;
  1348. for (Lines = 1; Lines < PPU.Mosaic - MosaicOffset; Lines++)
  1349. if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
  1350. (HOffset != LineData [Y + Lines].BG[bg].HOffset))
  1351. break;
  1352. uint32 MosaicLine = VOffset + Y - MosaicOffset;
  1353. if (Y + Lines > GFX.EndY)
  1354. Lines = GFX.EndY + 1 - Y;
  1355. uint32 VirtAlign = (MosaicLine & 7) << 3;
  1356. uint16 *b1;
  1357. uint16 *b2;
  1358. uint32 ScreenLine = MosaicLine >> OffsetShift;
  1359. uint32 Rem16 = MosaicLine & 15;
  1360. if (ScreenLine & 0x20)
  1361. b1 = SC2, b2 = SC3;
  1362. else
  1363. b1 = SC0, b2 = SC1;
  1364. b1 += (ScreenLine & 0x1f) << 5;
  1365. b2 += (ScreenLine & 0x1f) << 5;
  1366. uint16 *t;
  1367. uint32 Left = 0;
  1368. uint32 Right = 256 << m5;
  1369. HOffset <<= m5;
  1370. uint32 ClipCount = GFX.pCurrentClip->Count [bg];
  1371. uint32 HPos = HOffset;
  1372. uint32 PixWidth = (PPU.Mosaic << m5);
  1373. if (!ClipCount)
  1374. ClipCount = 1;
  1375. for (uint32 clip = 0; clip < ClipCount; clip++)
  1376. {
  1377. if (GFX.pCurrentClip->Count [bg])
  1378. {
  1379. Left = GFX.pCurrentClip->Left [clip][bg] << m5;
  1380. Right = GFX.pCurrentClip->Right [clip][bg] << m5;
  1381. uint32 r = Left % (PPU.Mosaic << m5);
  1382. HPos = HOffset + Left;
  1383. PixWidth = (PPU.Mosaic << m5) - r;
  1384. }
  1385. uint32 s = Y * GFX.PPL + Left * GFX.PixSize;
  1386. for (uint32 x = Left; x < Right; x += PixWidth,
  1387. s += (IPPU.HalfWidthPixels ? PixWidth >> 1 : PixWidth) * GFX.PixSize,
  1388. HPos += PixWidth, PixWidth = (PPU.Mosaic << m5))
  1389. {
  1390. uint32 Quot = (HPos & OffsetMask) >> 3;
  1391. if (x + PixWidth >= Right)
  1392. PixWidth = Right - x;
  1393. if (BG.TileSize == 8 && !m5)
  1394. {
  1395. if (Quot > 31)
  1396. t = b2 + (Quot & 0x1f);
  1397. else
  1398. t = b1 + Quot;
  1399. }
  1400. else
  1401. {
  1402. if (Quot > 63)
  1403. t = b2 + ((Quot >> 1) & 0x1f);
  1404. else
  1405. t = b1 + (Quot >> 1);
  1406. }
  1407. Tile = READ_2BYTES (t);
  1408. GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
  1409. // Draw tile...
  1410. if (BG.TileSize != 8)
  1411. {
  1412. if (Tile & H_FLIP)
  1413. {
  1414. // Horizontal flip, but what about vertical flip ?
  1415. if (Tile & V_FLIP)
  1416. {
  1417. // Both horzontal & vertical flip
  1418. if (Rem16 < 8)
  1419. {
  1420. (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
  1421. HPos & 7, PixWidth,
  1422. VirtAlign, Lines);
  1423. }
  1424. else
  1425. {
  1426. (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
  1427. HPos & 7, PixWidth,
  1428. VirtAlign, Lines);
  1429. }
  1430. }
  1431. else
  1432. {
  1433. // Horizontal flip only
  1434. if (Rem16 > 7)
  1435. {
  1436. (*DrawLargePixelPtr) (Tile + 17 - (Quot & 1), s,
  1437. HPos & 7, PixWidth,
  1438. VirtAlign, Lines);
  1439. }
  1440. else
  1441. {
  1442. (*DrawLargePixelPtr) (Tile + 1 - (Quot & 1), s,
  1443. HPos & 7, PixWidth,
  1444. VirtAlign, Lines);
  1445. }
  1446. }
  1447. }
  1448. else
  1449. {
  1450. // No horizontal flip, but is there a vertical flip ?
  1451. if (Tile & V_FLIP)
  1452. {
  1453. // Vertical flip only
  1454. if (Rem16 < 8)
  1455. {
  1456. (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
  1457. HPos & 7, PixWidth,
  1458. VirtAlign, Lines);
  1459. }
  1460. else
  1461. {
  1462. (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
  1463. HPos & 7, PixWidth,
  1464. VirtAlign, Lines);
  1465. }
  1466. }
  1467. else
  1468. {
  1469. // Normal unflipped
  1470. if (Rem16 > 7)
  1471. {
  1472. (*DrawLargePixelPtr) (Tile + 16 + (Quot & 1), s,
  1473. HPos & 7, PixWidth,
  1474. VirtAlign, Lines);
  1475. }
  1476. else
  1477. {
  1478. (*DrawLargePixelPtr) (Tile + (Quot & 1), s,
  1479. HPos & 7, PixWidth,
  1480. VirtAlign, Lines);
  1481. }
  1482. }
  1483. }
  1484. }
  1485. else
  1486. (*DrawLargePixelPtr) (Tile + (Quot & 1) * m5, s, HPos & 7, PixWidth,
  1487. VirtAlign, Lines);
  1488. }
  1489. }
  1490. }
  1491. }
  1492. static void DrawBackgroundOffset (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
  1493. {
  1494. CHECK_SOUND();
  1495. uint32 Tile;
  1496. uint16 *SC0;
  1497. uint16 *SC1;
  1498. uint16 *SC2;
  1499. uint16 *SC3;
  1500. uint16 *BPS0;
  1501. uint16 *BPS1;
  1502. uint16 *BPS2;
  1503. uint16 *BPS3;
  1504. uint32 Width;
  1505. int VOffsetOffset = BGMode == 4 ? 0 : 32;
  1506. uint8 depths [2] = {Z1, Z2};
  1507. BG.StartPalette = 0;
  1508. BPS0 = (uint16 *) &Memory.VRAM[PPU.BG[2].SCBase << 1];
  1509. if (PPU.BG[2].SCSize & 1)
  1510. BPS1 = BPS0 + 1024;
  1511. else
  1512. BPS1 = BPS0;
  1513. if (PPU.BG[2].SCSize & 2)
  1514. BPS2 = BPS1 + 1024;
  1515. else
  1516. BPS2 = BPS0;
  1517. if (PPU.BG[2].SCSize & 1)
  1518. BPS3 = BPS2 + 1024;
  1519. else
  1520. BPS3 = BPS2;
  1521. SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
  1522. if (PPU.BG[bg].SCSize & 1)
  1523. SC1 = SC0 + 1024;
  1524. else
  1525. SC1 = SC0;
  1526. if(((uint8*)SC1-Memory.VRAM)>=0x10000)
  1527. SC1-=0x08000;
  1528. if (PPU.BG[bg].SCSize & 2)
  1529. SC2 = SC1 + 1024;
  1530. else
  1531. SC2 = SC0;
  1532. if(((uint8*)SC2-Memory.VRAM)>=0x10000)
  1533. SC2-=0x08000;
  1534. if (PPU.BG[bg].SCSize & 1)
  1535. SC3 = SC2 + 1024;
  1536. else
  1537. SC3 = SC2;
  1538. if(((uint8*)SC3-Memory.VRAM)>=0x10000)
  1539. SC3-=0x08000;
  1540. static const int Lines = 1;
  1541. int OffsetMask;
  1542. int OffsetShift;
  1543. int OffsetEnableMask = 1 << (bg + 13);
  1544. if (BG.TileSize == 16)
  1545. {
  1546. OffsetMask = 0x3ff;
  1547. OffsetShift = 4;
  1548. }
  1549. else
  1550. {
  1551. OffsetMask = 0x1ff;
  1552. OffsetShift = 3;
  1553. }
  1554. for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y++)
  1555. {
  1556. uint32 VOff = LineData [Y].BG[2].VOffset - 1;
  1557. // uint32 VOff = LineData [Y].BG[2].VOffset;
  1558. uint32 HOff = LineData [Y].BG[2].HOffset;
  1559. int VirtAlign;
  1560. int ScreenLine = VOff >> 3;
  1561. int t1;
  1562. int t2;
  1563. uint16 *s0;
  1564. uint16 *s1;
  1565. uint16 *s2;
  1566. if (ScreenLine & 0x20)
  1567. s1 = BPS2, s2 = BPS3;
  1568. else
  1569. s1 = BPS0, s2 = BPS1;
  1570. s1 += (ScreenLine & 0x1f) << 5;
  1571. s2 += (ScreenLine & 0x1f) << 5;
  1572. if(BGMode != 4)
  1573. {
  1574. if((ScreenLine & 0x1f) == 0x1f)
  1575. {
  1576. if(ScreenLine & 0x20)
  1577. VOffsetOffset = BPS0 - BPS2 - 0x1f*32;
  1578. else
  1579. VOffsetOffset = BPS2 - BPS0 - 0x1f*32;
  1580. }
  1581. else
  1582. {
  1583. VOffsetOffset = 32;
  1584. }
  1585. }
  1586. int clipcount = GFX.pCurrentClip->Count [bg];
  1587. if (!clipcount)
  1588. clipcount = 1;
  1589. for (int clip = 0; clip < clipcount; clip++)
  1590. {
  1591. uint32 Left;
  1592. uint32 Right;
  1593. if (!GFX.pCurrentClip->Count [bg])
  1594. {
  1595. Left = 0;
  1596. Right = 256;
  1597. }
  1598. else
  1599. {
  1600. Left = GFX.pCurrentClip->Left [clip][bg];
  1601. Right = GFX.pCurrentClip->Right [clip][bg];
  1602. if (Right <= Left)
  1603. continue;
  1604. }
  1605. uint32 VOffset;
  1606. uint32 HOffset;
  1607. //added:
  1608. uint32 LineHOffset=LineData [Y].BG[bg].HOffset;
  1609. uint32 Offset;
  1610. uint32 HPos;
  1611. uint32 Quot;
  1612. uint32 Count;
  1613. uint16 *t;
  1614. uint32 Quot2;
  1615. uint32 VCellOffset;
  1616. uint32 HCellOffset;
  1617. uint16 *b1;
  1618. uint16 *b2;
  1619. uint32 TotalCount = 0;
  1620. uint32 MaxCount = 8;
  1621. uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
  1622. bool8 left_hand_edge = (Left == 0);
  1623. Width = Right - Left;
  1624. if (Left & 7)
  1625. MaxCount = 8 - (Left & 7);
  1626. while (Left < Right)
  1627. {
  1628. if (left_hand_edge)
  1629. {
  1630. // The SNES offset-per-tile background mode has a
  1631. // hardware limitation that the offsets cannot be set
  1632. // for the tile at the left-hand edge of the screen.
  1633. VOffset = LineData [Y].BG[bg].VOffset;
  1634. //MKendora; use temp var to reduce memory accesses
  1635. //HOffset = LineData [Y].BG[bg].HOffset;
  1636. HOffset = LineHOffset;
  1637. //End MK
  1638. left_hand_edge = FALSE;
  1639. }
  1640. else
  1641. {
  1642. // All subsequent offset tile data is shifted left by one,
  1643. // hence the - 1 below.
  1644. Quot2 = ((HOff + Left - 1) & OffsetMask) >> 3;
  1645. if (Quot2 > 31)
  1646. s0 = s2 + (Quot2 & 0x1f);
  1647. else
  1648. s0 = s1 + Quot2;
  1649. HCellOffset = READ_2BYTES (s0);
  1650. if (BGMode == 4)
  1651. {
  1652. VOffset = LineData [Y].BG[bg].VOffset;
  1653. //MKendora another mem access hack
  1654. //HOffset = LineData [Y].BG[bg].HOffset;
  1655. HOffset=LineHOffset;
  1656. //end MK
  1657. if ((HCellOffset & OffsetEnableMask))
  1658. {
  1659. if (HCellOffset & 0x8000)
  1660. VOffset = HCellOffset + 1;
  1661. else
  1662. HOffset = HCellOffset;
  1663. }
  1664. }
  1665. else
  1666. {
  1667. VCellOffset = READ_2BYTES (s0 + VOffsetOffset);
  1668. if ((VCellOffset & OffsetEnableMask))
  1669. VOffset = VCellOffset + 1;
  1670. else
  1671. VOffset = LineData [Y].BG[bg].VOffset;
  1672. //MKendora Strike Gunner fix
  1673. if ((HCellOffset & OffsetEnableMask))
  1674. {
  1675. //HOffset= HCellOffset;
  1676. HOffset = (HCellOffset & ~7)|(LineHOffset&7);
  1677. //HOffset |= LineData [Y].BG[bg].HOffset&7;
  1678. }
  1679. else
  1680. HOffset=LineHOffset;
  1681. //HOffset = LineData [Y].BG[bg].HOffset -
  1682. //Settings.StrikeGunnerOffsetHack;
  1683. //HOffset &= (~7);
  1684. //end MK
  1685. }
  1686. }
  1687. VirtAlign = ((Y + VOffset) & 7) << 3;
  1688. ScreenLine = (VOffset + Y) >> OffsetShift;
  1689. if (((VOffset + Y) & 15) > 7)
  1690. {
  1691. t1 = 16;
  1692. t2 = 0;
  1693. }
  1694. else
  1695. {
  1696. t1 = 0;
  1697. t2 = 16;
  1698. }
  1699. if (ScreenLine & 0x20)
  1700. b1 = SC2, b2 = SC3;
  1701. else
  1702. b1 = SC0, b2 = SC1;
  1703. b1 += (ScreenLine & 0x1f) << 5;
  1704. b2 += (ScreenLine & 0x1f) << 5;
  1705. HPos = (HOffset + Left) & OffsetMask;
  1706. Quot = HPos >> 3;
  1707. if (BG.TileSize == 8)
  1708. {
  1709. if (Quot > 31)
  1710. t = b2 + (Quot & 0x1f);
  1711. else
  1712. t = b1 + Quot;
  1713. }
  1714. else
  1715. {
  1716. if (Quot > 63)
  1717. t = b2 + ((Quot >> 1) & 0x1f);
  1718. else
  1719. t = b1 + (Quot >> 1);
  1720. }
  1721. if (MaxCount + TotalCount > Width)
  1722. MaxCount = Width - TotalCount;
  1723. Offset = HPos & 7;
  1724. //Count =1;
  1725. Count = 8 - Offset;
  1726. if (Count > MaxCount)
  1727. Count = MaxCount;
  1728. s -= (IPPU.HalfWidthPixels ? Offset >> 1 : Offset) * GFX.PixSize;
  1729. Tile = READ_2BYTES(t);
  1730. GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
  1731. if (BG.TileSize == 8)
  1732. (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign, Lines);
  1733. else
  1734. {
  1735. if (!(Tile & (V_FLIP | H_FLIP)))
  1736. {
  1737. // Normal, unflipped
  1738. (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
  1739. s, Offset, Count, VirtAlign, Lines);
  1740. }
  1741. else
  1742. if (Tile & H_FLIP)
  1743. {
  1744. if (Tile & V_FLIP)
  1745. {
  1746. // H & V flip
  1747. (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
  1748. s, Offset, Count, VirtAlign, Lines);
  1749. }
  1750. else
  1751. {
  1752. // H flip only
  1753. (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
  1754. s, Offset, Count, VirtAlign, Lines);
  1755. }
  1756. }
  1757. else
  1758. {
  1759. // V flip only
  1760. (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
  1761. s, Offset, Count, VirtAlign, Lines);
  1762. }
  1763. }
  1764. Left += Count;
  1765. TotalCount += Count;
  1766. s += (IPPU.HalfWidthPixe

Large files files are truncated, but you can click here to view the full file