PageRenderTime 70ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/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
  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.HalfWidthPixels ? (Offset + Count) >> 1 : (Offset + Count)) * GFX.PixSize;
  1767. MaxCount = 8;
  1768. }
  1769. }
  1770. }
  1771. }
  1772. static void DrawBackgroundMode5 (uint32 /* BGMODE */, uint32 bg, uint8 Z1, uint8 Z2)
  1773. {
  1774. CHECK_SOUND();
  1775. if(IPPU.Interlace)
  1776. {
  1777. GFX.Pitch = GFX.RealPitch;
  1778. GFX.PPL = GFX.PPLx2 >> 1;
  1779. }
  1780. GFX.PixSize = 1;
  1781. uint8 depths [2] = {Z1, Z2};
  1782. uint32 Tile;
  1783. uint16 *SC0;
  1784. uint16 *SC1;
  1785. uint16 *SC2;
  1786. uint16 *SC3;
  1787. uint32 Width;
  1788. BG.StartPalette = 0;
  1789. SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
  1790. if ((PPU.BG[bg].SCSize & 1))
  1791. SC1 = SC0 + 1024;
  1792. else
  1793. SC1 = SC0;
  1794. if((SC1-(unsigned short*)Memory.VRAM)>0x10000)
  1795. SC1=(uint16*)&Memory.VRAM[(((uint8*)SC1)-Memory.VRAM)%0x10000];
  1796. if ((PPU.BG[bg].SCSize & 2))
  1797. SC2 = SC1 + 1024;
  1798. else SC2 = SC0;
  1799. if(((uint8*)SC2-Memory.VRAM)>=0x10000)
  1800. SC2-=0x08000;
  1801. if ((PPU.BG[bg].SCSize & 1))
  1802. SC3 = SC2 + 1024;
  1803. else
  1804. SC3 = SC2;
  1805. if(((uint8*)SC3-Memory.VRAM)>=0x10000)
  1806. SC3-=0x08000;
  1807. int Lines;
  1808. int VOffsetMask;
  1809. int VOffsetShift;
  1810. if (BG.TileSize == 16)
  1811. {
  1812. VOffsetMask = 0x3ff;
  1813. VOffsetShift = 4;
  1814. }
  1815. else
  1816. {
  1817. VOffsetMask = 0x1ff;
  1818. VOffsetShift = 3;
  1819. }
  1820. int endy = IPPU.Interlace ? 1 + (GFX.EndY << 1) : GFX.EndY;
  1821. for (int Y = IPPU.Interlace ? GFX.StartY << 1 : GFX.StartY; Y <= endy; Y += Lines)
  1822. {
  1823. int y = IPPU.Interlace ? (Y >> 1) : Y;
  1824. uint32 VOffset = LineData [y].BG[bg].VOffset;
  1825. uint32 HOffset = LineData [y].BG[bg].HOffset;
  1826. int VirtAlign = (Y + VOffset) & 7;
  1827. for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
  1828. if ((VOffset != LineData [y + Lines].BG[bg].VOffset) ||
  1829. (HOffset != LineData [y + Lines].BG[bg].HOffset))
  1830. break;
  1831. HOffset <<= 1;
  1832. if (Y + Lines > endy)
  1833. Lines = endy + 1 - Y;
  1834. VirtAlign <<= 3;
  1835. int ScreenLine = (VOffset + Y) >> VOffsetShift;
  1836. int t1;
  1837. int t2;
  1838. if (((VOffset + Y) & 15) > 7)
  1839. {
  1840. t1 = 16;
  1841. t2 = 0;
  1842. }
  1843. else
  1844. {
  1845. t1 = 0;
  1846. t2 = 16;
  1847. }
  1848. uint16 *b1;
  1849. uint16 *b2;
  1850. if (ScreenLine & 0x20)
  1851. b1 = SC2, b2 = SC3;
  1852. else
  1853. b1 = SC0, b2 = SC1;
  1854. b1 += (ScreenLine & 0x1f) << 5;
  1855. b2 += (ScreenLine & 0x1f) << 5;
  1856. int clipcount = GFX.pCurrentClip->Count [bg];
  1857. if (!clipcount)
  1858. clipcount = 1;
  1859. for (int clip = 0; clip < clipcount; clip++)
  1860. {
  1861. int Left;
  1862. int Right;
  1863. if (!GFX.pCurrentClip->Count [bg])
  1864. {
  1865. Left = 0;
  1866. Right = 512;
  1867. }
  1868. else
  1869. {
  1870. Left = GFX.pCurrentClip->Left [clip][bg] * 2;
  1871. Right = GFX.pCurrentClip->Right [clip][bg] * 2;
  1872. if (Right <= Left)
  1873. continue;
  1874. }
  1875. uint32 s = (IPPU.HalfWidthPixels ? Left >> 1 : Left) * GFX.PixSize + Y * GFX.PPL;
  1876. uint32 HPos = (HOffset + Left * GFX.PixSize) & 0x3ff;
  1877. uint32 Quot = HPos >> 3;
  1878. uint32 Count = 0;
  1879. uint16 *t;
  1880. if (Quot > 63)
  1881. t = b2 + ((Quot >> 1) & 0x1f);
  1882. else
  1883. t = b1 + (Quot >> 1);
  1884. Width = Right - Left;
  1885. // Left hand edge clipped tile
  1886. if (HPos & 7)
  1887. {
  1888. int Offset = (HPos & 7);
  1889. Count = 8 - Offset;
  1890. if (Count > Width)
  1891. Count = Width;
  1892. s -= (IPPU.HalfWidthPixels ? Offset >> 1 : Offset);
  1893. Tile = READ_2BYTES (t);
  1894. GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
  1895. if (BG.TileSize == 8)
  1896. {
  1897. if (!(Tile & H_FLIP))
  1898. {
  1899. // Normal, unflipped
  1900. (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
  1901. s, Offset, Count, VirtAlign, Lines);
  1902. }
  1903. else
  1904. {
  1905. // H flip
  1906. (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
  1907. s, Offset, Count, VirtAlign, Lines);
  1908. }
  1909. }
  1910. else
  1911. {
  1912. if (!(Tile & (V_FLIP | H_FLIP)))
  1913. {
  1914. // Normal, unflipped
  1915. (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
  1916. s, Offset, Count, VirtAlign, Lines);
  1917. }
  1918. else
  1919. if (Tile & H_FLIP)
  1920. {
  1921. if (Tile & V_FLIP)
  1922. {
  1923. // H & V flip
  1924. (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
  1925. s, Offset, Count, VirtAlign, Lines);
  1926. }
  1927. else
  1928. {
  1929. // H flip only
  1930. (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
  1931. s, Offset, Count, VirtAlign, Lines);
  1932. }
  1933. }
  1934. else
  1935. {
  1936. // V flip only
  1937. (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
  1938. s, Offset, Count, VirtAlign, Lines);
  1939. }
  1940. }
  1941. t += Quot & 1;
  1942. if (Quot == 63)
  1943. t = b2;
  1944. else if (Quot == 127)
  1945. t = b1;
  1946. Quot++;
  1947. s += (IPPU.HalfWidthPixels ? 4 : 8);
  1948. }
  1949. // Middle, unclipped tiles
  1950. Count = Width - Count;
  1951. int Middle = Count >> 3;
  1952. Count &= 7;
  1953. for (int C = Middle; C > 0; s += (IPPU.HalfWidthPixels ? 4 : 8), Quot++, C--)
  1954. {
  1955. Tile = READ_2BYTES(t);
  1956. GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
  1957. if (BG.TileSize == 8)
  1958. {
  1959. if (!(Tile & H_FLIP))
  1960. {
  1961. // Normal, unflipped
  1962. (*DrawHiResTilePtr) (Tile + (Quot & 1),
  1963. s, VirtAlign, Lines);
  1964. }
  1965. else
  1966. {
  1967. // H flip
  1968. (*DrawHiResTilePtr) (Tile + 1 - (Quot & 1),
  1969. s, VirtAlign, Lines);
  1970. }
  1971. }
  1972. else
  1973. {
  1974. if (!(Tile & (V_FLIP | H_FLIP)))
  1975. {
  1976. // Normal, unflipped
  1977. (*DrawHiResTilePtr) (Tile + t1 + (Quot & 1),
  1978. s, VirtAlign, Lines);
  1979. }
  1980. else
  1981. if (Tile & H_FLIP)
  1982. {
  1983. if (Tile & V_FLIP)
  1984. {
  1985. // H & V flip
  1986. (*DrawHiResTilePtr) (Tile + t2 + 1 - (Quot & 1),
  1987. s, VirtAlign, Lines);
  1988. }
  1989. else
  1990. {
  1991. // H flip only
  1992. (*DrawHiResTilePtr) (Tile + t1 + 1 - (Quot & 1),
  1993. s, VirtAlign, Lines);
  1994. }
  1995. }
  1996. else
  1997. {
  1998. // V flip only
  1999. (*DrawHiResTilePtr) (Tile + t2 + (Quot & 1),
  2000. s, VirtAlign, Lines);
  2001. }
  2002. }
  2003. t += Quot & 1;
  2004. if (Quot == 63)
  2005. t = b2;
  2006. else
  2007. if (Quot == 127)
  2008. t = b1;
  2009. }
  2010. // Right-hand edge clipped tiles
  2011. if (Count)
  2012. {
  2013. Tile = READ_2BYTES(t);
  2014. GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
  2015. if (BG.TileSize == 8)
  2016. {
  2017. if (!(Tile & H_FLIP))
  2018. {
  2019. // Normal, unflipped
  2020. (*DrawHiResClippedTilePtr) (Tile + (Quot & 1),
  2021. s, 0, Count, VirtAlign, Lines);
  2022. }
  2023. else
  2024. {
  2025. // H flip
  2026. (*DrawHiResClippedTilePtr) (Tile + 1 - (Quot & 1),
  2027. s, 0, Count, VirtAlign, Lines);
  2028. }
  2029. }
  2030. else
  2031. {
  2032. if (!(Tile & (V_FLIP | H_FLIP)))
  2033. {
  2034. // Normal, unflipped
  2035. (*DrawHiResClippedTilePtr) (Tile + t1 + (Quot & 1),
  2036. s, 0, Count, VirtAlign, Lines);
  2037. }
  2038. else
  2039. if (Tile & H_FLIP)
  2040. {
  2041. if (Tile & V_FLIP)
  2042. {
  2043. // H & V flip
  2044. (*DrawHiResClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
  2045. s, 0, Count, VirtAlign, Lines);
  2046. }
  2047. else
  2048. {
  2049. // H flip only
  2050. (*DrawHiResClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
  2051. s, 0, Count, VirtAlign, Lines);
  2052. }
  2053. }
  2054. else
  2055. {
  2056. // V flip only
  2057. (*DrawHiResClippedTilePtr) (Tile + t2 + (Quot & 1),
  2058. s, 0, Count, VirtAlign, Lines);
  2059. }
  2060. }
  2061. }
  2062. }
  2063. }
  2064. GFX.Pitch = IPPU.DoubleHeightPixels ? GFX.RealPitch * 2 : GFX.RealPitch;
  2065. GFX.PPL = IPPU.DoubleHeightPixels ? GFX.PPLx2 : (GFX.PPLx2 >> 1);
  2066. }
  2067. static void DrawBackground (uint32 BGMode, uint32 bg, uint8 Z1, uint8 Z2)
  2068. {
  2069. #ifdef ACCUMULATE_JOYPAD
  2070. /*
  2071. * This call allows NDSSFC to synchronise the DS controller more often.
  2072. * If porting a later version of Snes9x into NDSSFC, it is essential to
  2073. * preserve it.
  2074. */
  2075. NDSSFCAccumulateJoypad ();
  2076. #endif
  2077. GFX.PixSize = 1;
  2078. BG.TileSize = BGSizes [PPU.BG[bg].BGSize];
  2079. BG.BitShift = BitShifts[BGMode][bg];
  2080. BG.TileShift = TileShifts[BGMode][bg];
  2081. BG.TileAddress = PPU.BG[bg].NameBase << 1;
  2082. BG.NameSelect = 0;
  2083. BG.Buffer = IPPU.TileCache [Depths [BGMode][bg]];
  2084. BG.Buffered = IPPU.TileCached [Depths [BGMode][bg]];
  2085. BG.PaletteShift = PaletteShifts[BGMode][bg];
  2086. BG.PaletteMask = PaletteMasks[BGMode][bg];
  2087. BG.DirectColourMode = (BGMode == 3 || BGMode == 4) && bg == 0 &&
  2088. (GFX.r2130 & 1);
  2089. if (PPU.BGMosaic [bg] && PPU.Mosaic > 1)
  2090. {
  2091. DrawBackgroundMosaic (BGMode, bg, Z1, Z2);
  2092. return;
  2093. }
  2094. switch (BGMode)
  2095. {
  2096. case 2:
  2097. case 4: // Used by Puzzle Bobble
  2098. DrawBackgroundOffset (BGMode, bg, Z1, Z2);
  2099. return;
  2100. case 5:
  2101. case 6: // XXX: is also offset per tile.
  2102. // if (Settings.SupportHiRes)
  2103. // {
  2104. if (!Settings.SupportHiRes)
  2105. SelectTileRenderer(TRUE /* normal */);
  2106. DrawBackgroundMode5 (BGMode, bg, Z1, Z2);
  2107. return;
  2108. // }
  2109. break;
  2110. }
  2111. CHECK_SOUND();
  2112. uint32 Tile;
  2113. uint16 *SC0;
  2114. uint16 *SC1;
  2115. uint16 *SC2;
  2116. uint16 *SC3;
  2117. uint32 Width;
  2118. uint8 depths [2] = {Z1, Z2};
  2119. if (BGMode == 0)
  2120. BG.StartPalette = bg << 5;
  2121. else BG.StartPalette = 0;
  2122. SC0 = (uint16 *) &Memory.VRAM[PPU.BG[bg].SCBase << 1];
  2123. if (PPU.BG[bg].SCSize & 1)
  2124. SC1 = SC0 + 1024;
  2125. else
  2126. SC1 = SC0;
  2127. if(SC1>=(unsigned short*)(Memory.VRAM+0x10000))
  2128. SC1=(uint16*)&Memory.VRAM[((uint8*)SC1-&Memory.VRAM[0])%0x10000];
  2129. if (PPU.BG[bg].SCSize & 2)
  2130. SC2 = SC1 + 1024;
  2131. else
  2132. SC2 = SC0;
  2133. if(((uint8*)SC2-Memory.VRAM)>=0x10000)
  2134. SC2-=0x08000;
  2135. if (PPU.BG[bg].SCSize & 1)
  2136. SC3 = SC2 + 1024;
  2137. else
  2138. SC3 = SC2;
  2139. if(((uint8*)SC3-Memory.VRAM)>=0x10000)
  2140. SC3-=0x08000;
  2141. int Lines;
  2142. int OffsetMask;
  2143. int OffsetShift;
  2144. if (BG.TileSize == 16)
  2145. {
  2146. OffsetMask = 0x3ff;
  2147. OffsetShift = 4;
  2148. }
  2149. else
  2150. {
  2151. OffsetMask = 0x1ff;
  2152. OffsetShift = 3;
  2153. }
  2154. for (uint32 Y = GFX.StartY; Y <= GFX.EndY; Y += Lines)
  2155. {
  2156. uint32 VOffset = LineData [Y].BG[bg].VOffset;
  2157. uint32 HOffset = LineData [Y].BG[bg].HOffset;
  2158. int VirtAlign = (Y + VOffset) & 7;
  2159. for (Lines = 1; Lines < 8 - VirtAlign; Lines++)
  2160. if ((VOffset != LineData [Y + Lines].BG[bg].VOffset) ||
  2161. (HOffset != LineData [Y + Lines].BG[bg].HOffset))
  2162. break;
  2163. if (Y + Lines > GFX.EndY)
  2164. Lines = GFX.EndY + 1 - Y;
  2165. VirtAlign <<= 3;
  2166. uint32 ScreenLine = (VOffset + Y) >> OffsetShift;
  2167. uint32 t1;
  2168. uint32 t2;
  2169. if (((VOffset + Y) & 15) > 7)
  2170. {
  2171. t1 = 16;
  2172. t2 = 0;
  2173. }
  2174. else
  2175. {
  2176. t1 = 0;
  2177. t2 = 16;
  2178. }
  2179. uint16 *b1;
  2180. uint16 *b2;
  2181. if (ScreenLine & 0x20)
  2182. b1 = SC2, b2 = SC3;
  2183. else
  2184. b1 = SC0, b2 = SC1;
  2185. b1 += (ScreenLine & 0x1f) << 5;
  2186. b2 += (ScreenLine & 0x1f) << 5;
  2187. int clipcount = GFX.pCurrentClip->Count [bg];
  2188. if (!clipcount)
  2189. clipcount = 1;
  2190. for (int clip = 0; clip < clipcount; clip++)
  2191. {
  2192. uint32 Left;
  2193. uint32 Right;
  2194. if (!GFX.pCurrentClip->Count [bg])
  2195. {
  2196. Left = 0;
  2197. Right = 256;
  2198. }
  2199. else
  2200. {
  2201. Left = GFX.pCurrentClip->Left [clip][bg];
  2202. Right = GFX.pCurrentClip->Right [clip][bg];
  2203. if (Right <= Left)
  2204. continue;
  2205. }
  2206. uint32 s = Left * GFX.PixSize + Y * GFX.PPL;
  2207. uint32 HPos = (HOffset + Left) & OffsetMask;
  2208. uint32 Quot = HPos >> 3;
  2209. uint32 Count = 0;
  2210. uint16 *t;
  2211. if (BG.TileSize == 8)
  2212. {
  2213. if (Quot > 31)
  2214. t = b2 + (Quot & 0x1f);
  2215. else
  2216. t = b1 + Quot;
  2217. }
  2218. else
  2219. {
  2220. if (Quot > 63)
  2221. t = b2 + ((Quot >> 1) & 0x1f);
  2222. else
  2223. t = b1 + (Quot >> 1);
  2224. }
  2225. Width = Right - Left;
  2226. // Left hand edge clipped tile
  2227. if (HPos & 7)
  2228. {
  2229. uint32 Offset = (HPos & 7);
  2230. Count = 8 - Offset;
  2231. if (Count > Width)
  2232. Count = Width;
  2233. s -= Offset * GFX.PixSize;
  2234. Tile = READ_2BYTES(t);
  2235. GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
  2236. if (BG.TileSize == 8)
  2237. {
  2238. (*DrawClippedTilePtr) (Tile, s, Offset, Count, VirtAlign,
  2239. Lines);
  2240. }
  2241. else
  2242. {
  2243. if (!(Tile & (V_FLIP | H_FLIP)))
  2244. {
  2245. // Normal, unflipped
  2246. (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1),
  2247. s, Offset, Count, VirtAlign, Lines);
  2248. }
  2249. else
  2250. if (Tile & H_FLIP)
  2251. {
  2252. if (Tile & V_FLIP)
  2253. {
  2254. // H & V flip
  2255. (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
  2256. s, Offset, Count, VirtAlign, Lines);
  2257. }
  2258. else
  2259. {
  2260. // H flip only
  2261. (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
  2262. s, Offset, Count, VirtAlign, Lines);
  2263. }
  2264. }
  2265. else
  2266. {
  2267. // V flip only
  2268. (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1), s,
  2269. Offset, Count, VirtAlign, Lines);
  2270. }
  2271. }
  2272. if (BG.TileSize == 8)
  2273. {
  2274. t++;
  2275. if (Quot == 31)
  2276. t = b2;
  2277. else if (Quot == 63)
  2278. t = b1;
  2279. }
  2280. else
  2281. {
  2282. t += Quot & 1;
  2283. if (Quot == 63)
  2284. t = b2;
  2285. else if (Quot == 127)
  2286. t = b1;
  2287. }
  2288. Quot++;
  2289. s += (IPPU.HalfWidthPixels ? 4 : 8) * GFX.PixSize;
  2290. }
  2291. // Middle, unclipped tiles
  2292. Count = Width - Count;
  2293. int Middle = Count >> 3;
  2294. Count &= 7;
  2295. for (int C = Middle; C > 0; s += (IPPU.HalfWidthPixels ? 4 : 8) * GFX.PixSize, Quot++, C--)
  2296. {
  2297. Tile = READ_2BYTES(t);
  2298. GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
  2299. if (BG.TileSize != 8)
  2300. {
  2301. if (Tile & H_FLIP)
  2302. {
  2303. // Horizontal flip, but what about vertical flip ?
  2304. if (Tile & V_FLIP)
  2305. {
  2306. // Both horzontal & vertical flip
  2307. (*DrawTilePtr) (Tile + t2 + 1 - (Quot & 1), s,
  2308. VirtAlign, Lines);
  2309. }
  2310. else
  2311. {
  2312. // Horizontal flip only
  2313. (*DrawTilePtr) (Tile + t1 + 1 - (Quot & 1), s,
  2314. VirtAlign, Lines);
  2315. }
  2316. }
  2317. else
  2318. {
  2319. // No horizontal flip, but is there a vertical flip ?
  2320. if (Tile & V_FLIP)
  2321. {
  2322. // Vertical flip only
  2323. (*DrawTilePtr) (Tile + t2 + (Quot & 1), s,
  2324. VirtAlign, Lines);
  2325. }
  2326. else
  2327. {
  2328. // Normal unflipped
  2329. (*DrawTilePtr) (Tile + t1 + (Quot & 1), s,
  2330. VirtAlign, Lines);
  2331. }
  2332. }
  2333. }
  2334. else
  2335. {
  2336. (*DrawTilePtr) (Tile, s, VirtAlign, Lines);
  2337. }
  2338. if (BG.TileSize == 8)
  2339. {
  2340. t++;
  2341. if (Quot == 31)
  2342. t = b2;
  2343. else
  2344. if (Quot == 63)
  2345. t = b1;
  2346. }
  2347. else
  2348. {
  2349. t += Quot & 1;
  2350. if (Quot == 63)
  2351. t = b2;
  2352. else
  2353. if (Quot == 127)
  2354. t = b1;
  2355. }
  2356. }
  2357. // Right-hand edge clipped tiles
  2358. if (Count)
  2359. {
  2360. Tile = READ_2BYTES(t);
  2361. GFX.Z1 = GFX.Z2 = depths [(Tile & 0x2000) >> 13];
  2362. if (BG.TileSize == 8)
  2363. (*DrawClippedTilePtr) (Tile, s, 0, Count, VirtAlign,
  2364. Lines);
  2365. else
  2366. {
  2367. if (!(Tile & (V_FLIP | H_FLIP)))
  2368. {
  2369. // Normal, unflipped
  2370. (*DrawClippedTilePtr) (Tile + t1 + (Quot & 1), s, 0,
  2371. Count, VirtAlign, Lines);
  2372. }
  2373. else if (Tile & H_FLIP)
  2374. {
  2375. if (Tile & V_FLIP)
  2376. {
  2377. // H & V flip
  2378. (*DrawClippedTilePtr) (Tile + t2 + 1 - (Quot & 1),
  2379. s, 0, Count, VirtAlign,
  2380. Lines);
  2381. }
  2382. else
  2383. {
  2384. // H flip only
  2385. (*DrawClippedTilePtr) (Tile + t1 + 1 - (Quot & 1),
  2386. s, 0, Count, VirtAlign,
  2387. Lines);
  2388. }
  2389. }
  2390. else
  2391. {
  2392. // V flip only
  2393. (*DrawClippedTilePtr) (Tile + t2 + (Quot & 1),
  2394. s, 0, Count, VirtAlign,
  2395. Lines);
  2396. }
  2397. }
  2398. }
  2399. }
  2400. }
  2401. }
  2402. #define RENDER_BACKGROUND_MODE7(TYPE,FUNC) \
  2403. uint16 *ScreenColors; \
  2404. CHECK_SOUND(); \
  2405. \
  2406. uint8 *VRAM1 = Memory.VRAM + 1; \
  2407. if (GFX.r2130 & 1) \
  2408. { \
  2409. if (IPPU.DirectColourMapsNeedRebuild) \
  2410. S9xBuildDirectColourMaps (); \
  2411. ScreenColors = DirectColourMaps [0]; \
  2412. } \
  2413. else \
  2414. ScreenColors = IPPU.ScreenColors; \
  2415. \
  2416. int aa, cc; \
  2417. int dir; \
  2418. int startx, endx; \
  2419. uint32 Left = 0; \
  2420. uint32 Right = 256; \
  2421. uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
  2422. \
  2423. if (!ClipCount) \
  2424. ClipCount = 1; \
  2425. \
  2426. Screen += GFX.StartY * GFX.Pitch; \
  2427. uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
  2428. struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
  2429. \
  2430. for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
  2431. { \
  2432. int yy; \
  2433. \
  2434. int32 HOffset = ((int32) LineData [Line].BG[0].HOffset << M7) >> M7; \
  2435. int32 VOffset = ((int32) LineData [Line].BG[0].VOffset << M7) >> M7; \
  2436. \
  2437. int32 CentreX = ((int32) l->CentreX << M7) >> M7; \
  2438. int32 CentreY = ((int32) l->CentreY << M7) >> M7; \
  2439. \
  2440. if (PPU.Mode7VFlip) \
  2441. yy = 255 - (int) Line; \
  2442. else \
  2443. yy = Line; \
  2444. \
  2445. yy += CLIP_10_BIT_SIGNED(VOffset - CentreY); \
  2446. \
  2447. int BB = l->MatrixB * yy + (CentreX << 8); \
  2448. int DD = l->MatrixD * yy + (CentreY << 8); \
  2449. \
  2450. for (uint32 clip = 0; clip < ClipCount; clip++) \
  2451. { \
  2452. if (GFX.pCurrentClip->Count [bg]) \
  2453. { \
  2454. Left = GFX.pCurrentClip->Left [clip][bg]; \
  2455. Right = GFX.pCurrentClip->Right [clip][bg]; \
  2456. if (Right <= Left) \
  2457. continue; \
  2458. } \
  2459. TYPE *p = (TYPE *) Screen + Left; \
  2460. uint8 *d = Depth + Left; \
  2461. \
  2462. if (PPU.Mode7HFlip) \
  2463. { \
  2464. startx = Right - 1; \
  2465. endx = Left - 1; \
  2466. dir = -1; \
  2467. aa = -l->MatrixA; \
  2468. cc = -l->MatrixC; \
  2469. } \
  2470. else \
  2471. { \
  2472. startx = Left; \
  2473. endx = Right; \
  2474. dir = 1; \
  2475. aa = l->MatrixA; \
  2476. cc = l->MatrixC; \
  2477. } \
  2478. \
  2479. int xx = startx + CLIP_10_BIT_SIGNED(HOffset - CentreX); \
  2480. int AA = l->MatrixA * xx; \
  2481. int CC = l->MatrixC * xx; \
  2482. \
  2483. if (!PPU.Mode7Repeat) \
  2484. { \
  2485. for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
  2486. { \
  2487. int X = ((AA + BB) >> 8) & 0x3ff; \
  2488. int Y = ((CC + DD) >> 8) & 0x3ff; \
  2489. uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
  2490. uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
  2491. GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
  2492. if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
  2493. { \
  2494. *p = (FUNC); \
  2495. *d = GFX.Z1; \
  2496. } \
  2497. } \
  2498. } \
  2499. else \
  2500. { \
  2501. for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
  2502. { \
  2503. int X = ((AA + BB) >> 8); \
  2504. int Y = ((CC + DD) >> 8); \
  2505. \
  2506. if (((X | Y) & ~0x3ff) == 0) \
  2507. { \
  2508. uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
  2509. uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
  2510. GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
  2511. if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
  2512. { \
  2513. *p = (FUNC); \
  2514. *d = GFX.Z1; \
  2515. } \
  2516. } \
  2517. else \
  2518. { \
  2519. if (PPU.Mode7Repeat == 3) \
  2520. { \
  2521. X = (x + HOffset) & 7; \
  2522. Y = (yy + CentreY) & 7; \
  2523. uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
  2524. GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
  2525. if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
  2526. { \
  2527. *p = (FUNC); \
  2528. *d = GFX.Z1; \
  2529. } \
  2530. } \
  2531. } \
  2532. } \
  2533. } \
  2534. } \
  2535. }
  2536. static void DrawBGMode7Background (uint8 *Screen, int bg)
  2537. {
  2538. RENDER_BACKGROUND_MODE7 (uint8, (uint8) (b & GFX.Mode7Mask))
  2539. }
  2540. static void DrawBGMode7Background16 (uint8 *Screen, int bg)
  2541. {
  2542. RENDER_BACKGROUND_MODE7 (uint16, ScreenColors [b & GFX.Mode7Mask]);
  2543. }
  2544. static void DrawBGMode7Background16Add (uint8 *Screen, int bg)
  2545. {
  2546. RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
  2547. (*(d + GFX.DepthDelta) != 1 ?
  2548. COLOR_ADD (ScreenColors [b & GFX.Mode7Mask],
  2549. p [GFX.Delta]) :
  2550. COLOR_ADD (ScreenColors [b & GFX.Mode7Mask],
  2551. GFX.FixedColour)) :
  2552. ScreenColors [b & GFX.Mode7Mask]);
  2553. }
  2554. static void DrawBGMode7Background16Add1_2 (uint8 *Screen, int bg)
  2555. {
  2556. RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
  2557. (*(d + GFX.DepthDelta) != 1 ?
  2558. COLOR_ADD1_2 (ScreenColors [b & GFX.Mode7Mask],
  2559. p [GFX.Delta]) :
  2560. COLOR_ADD (ScreenColors [b & GFX.Mode7Mask],
  2561. GFX.FixedColour)) :
  2562. ScreenColors [b & GFX.Mode7Mask]);
  2563. }
  2564. static void DrawBGMode7Background16Sub (uint8 *Screen, int bg)
  2565. {
  2566. RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
  2567. (*(d + GFX.DepthDelta) != 1 ?
  2568. COLOR_SUB (ScreenColors [b & GFX.Mode7Mask],
  2569. p [GFX.Delta]) :
  2570. COLOR_SUB (ScreenColors [b & GFX.Mode7Mask],
  2571. GFX.FixedColour)) :
  2572. ScreenColors [b & GFX.Mode7Mask]);
  2573. }
  2574. static void DrawBGMode7Background16Sub1_2 (uint8 *Screen, int bg)
  2575. {
  2576. RENDER_BACKGROUND_MODE7 (uint16, *(d + GFX.DepthDelta) ?
  2577. (*(d + GFX.DepthDelta) != 1 ?
  2578. COLOR_SUB1_2 (ScreenColors [b & GFX.Mode7Mask],
  2579. p [GFX.Delta]) :
  2580. COLOR_SUB (ScreenColors [b & GFX.Mode7Mask],
  2581. GFX.FixedColour)) :
  2582. ScreenColors [b & GFX.Mode7Mask]);
  2583. }
  2584. #define RENDER_BACKGROUND_MODE7_i(TYPE,FUNC,COLORFUNC) \
  2585. uint16 *ScreenColors; \
  2586. CHECK_SOUND(); \
  2587. \
  2588. uint8 *VRAM1 = Memory.VRAM + 1; \
  2589. if (GFX.r2130 & 1) \
  2590. { \
  2591. if (IPPU.DirectColourMapsNeedRebuild) \
  2592. S9xBuildDirectColourMaps (); \
  2593. ScreenColors = DirectColourMaps [0]; \
  2594. } \
  2595. else \
  2596. ScreenColors = IPPU.ScreenColors; \
  2597. \
  2598. int aa, cc; \
  2599. int dir; \
  2600. int startx, endx; \
  2601. uint32 Left = 0; \
  2602. uint32 Right = 256; \
  2603. uint32 ClipCount = GFX.pCurrentClip->Count [bg]; \
  2604. \
  2605. if (!ClipCount) \
  2606. ClipCount = 1; \
  2607. \
  2608. Screen += GFX.StartY * GFX.Pitch; \
  2609. uint8 *Depth = GFX.DB + GFX.StartY * GFX.PPL; \
  2610. struct SLineMatrixData *l = &LineMatrixData [GFX.StartY]; \
  2611. bool8 allowSimpleCase = FALSE; \
  2612. if (!l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100) \
  2613. && !LineMatrixData[GFX.EndY].MatrixB && !LineMatrixData[GFX.EndY].MatrixC \
  2614. && (LineMatrixData[GFX.EndY].MatrixA == 0x0100) && (LineMatrixData[GFX.EndY].MatrixD == 0x0100) \
  2615. ) \
  2616. allowSimpleCase = TRUE; \
  2617. \
  2618. for (uint32 Line = GFX.StartY; Line <= GFX.EndY; Line++, Screen += GFX.Pitch, Depth += GFX.PPL, l++) \
  2619. { \
  2620. int yy; \
  2621. \
  2622. int HOffset = ((int) LineData [Line].BG[0].HOffset << M7) >> M7; \
  2623. int VOffset = ((int) LineData [Line].BG[0].VOffset << M7) >> M7; \
  2624. \
  2625. int CentreX = ((int) l->CentreX << M7) >> M7; \
  2626. int CentreY = ((int) l->CentreY << M7) >> M7; \
  2627. \
  2628. if (PPU.Mode7VFlip) \
  2629. yy = 255 - (int) Line; \
  2630. else \
  2631. yy = Line; \
  2632. \
  2633. \
  2634. yy += CLIP_10_BIT_SIGNED(VOffset - CentreY); \
  2635. bool8 simpleCase = FALSE; \
  2636. int BB; \
  2637. int DD; \
  2638. /* Make a special case for the identity matrix, since it's a common case and */ \
  2639. /* can be done much more quickly without special effects */ \
  2640. if (allowSimpleCase && !l->MatrixB && !l->MatrixC && (l->MatrixA == 0x0100) && (l->MatrixD == 0x0100)) \
  2641. { \
  2642. BB = CentreX << 8; \
  2643. DD = (yy + CentreY) << 8; \
  2644. simpleCase = TRUE; \
  2645. } \
  2646. else \
  2647. { \
  2648. BB = l->MatrixB * yy + (CentreX << 8); \
  2649. DD = l->MatrixD * yy + (CentreY << 8); \
  2650. } \
  2651. \
  2652. for (uint32 clip = 0; clip < ClipCount; clip++) \
  2653. { \
  2654. if (GFX.pCurrentClip->Count [bg]) \
  2655. { \
  2656. Left = GFX.pCurrentClip->Left [clip][bg]; \
  2657. Right = GFX.pCurrentClip->Right [clip][bg]; \
  2658. if (Right <= Left) \
  2659. continue; \
  2660. } \
  2661. TYPE *p = (TYPE *) Screen + Left; \
  2662. uint8 *d = Depth + Left; \
  2663. \
  2664. if (PPU.Mode7HFlip) \
  2665. { \
  2666. startx = Right - 1; \
  2667. endx = Left - 1; \
  2668. dir = -1; \
  2669. aa = -l->MatrixA; \
  2670. cc = -l->MatrixC; \
  2671. } \
  2672. else \
  2673. { \
  2674. startx = Left; \
  2675. endx = Right; \
  2676. dir = 1; \
  2677. aa = l->MatrixA; \
  2678. cc = l->MatrixC; \
  2679. } \
  2680. int xx; \
  2681. \
  2682. xx = startx + CLIP_10_BIT_SIGNED(HOffset - CentreX); \
  2683. int AA, CC = 0; \
  2684. if (simpleCase) \
  2685. { \
  2686. AA = xx << 8; \
  2687. } \
  2688. else \
  2689. { \
  2690. AA = l->MatrixA * xx; \
  2691. CC = l->MatrixC * xx; \
  2692. } \
  2693. if (simpleCase) \
  2694. { \
  2695. if (!PPU.Mode7Repeat) \
  2696. { \
  2697. int x = startx; \
  2698. do \
  2699. { \
  2700. int X = ((AA + BB) >> 8) & 0x3ff; \
  2701. int Y = (DD >> 8) & 0x3ff; \
  2702. uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
  2703. uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
  2704. GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
  2705. if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
  2706. { \
  2707. TYPE theColor = COLORFUNC; \
  2708. *p = (FUNC) | ALPHA_BITS_MASK; \
  2709. *d = GFX.Z1; \
  2710. } \
  2711. AA += aa, p++, d++; \
  2712. x += dir; \
  2713. } while (x != endx); \
  2714. } \
  2715. else \
  2716. { \
  2717. int x = startx; \
  2718. do { \
  2719. int X = (AA + BB) >> 8; \
  2720. int Y = DD >> 8; \
  2721. \
  2722. if (((X | Y) & ~0x3ff) == 0) \
  2723. { \
  2724. uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
  2725. uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
  2726. GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
  2727. if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
  2728. { \
  2729. TYPE theColor = COLORFUNC; \
  2730. *p = (FUNC) | ALPHA_BITS_MASK; \
  2731. *d = GFX.Z1; \
  2732. } \
  2733. } \
  2734. else if (PPU.Mode7Repeat == 3) \
  2735. { \
  2736. X = (x + HOffset) & 7; \
  2737. Y = (yy + CentreY) & 7; \
  2738. uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
  2739. uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
  2740. GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
  2741. if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
  2742. { \
  2743. TYPE theColor = COLORFUNC; \
  2744. *p = (FUNC) | ALPHA_BITS_MASK; \
  2745. *d = GFX.Z1; \
  2746. } \
  2747. } \
  2748. AA += aa; p++; d++; \
  2749. x += dir; \
  2750. } while (x != endx); \
  2751. } \
  2752. } \
  2753. else if (!PPU.Mode7Repeat) \
  2754. { \
  2755. /* The bilinear interpolator: get the colors at the four points surrounding */ \
  2756. /* the location of one point in the _sampled_ image, and weight them according */ \
  2757. /* to their (city block) distance. It's very smooth, but blurry with "close up" */ \
  2758. /* points. */ \
  2759. \
  2760. /* 460 (slightly less than 2 source pixels per displayed pixel) is an educated */ \
  2761. /* guess for where bilinear filtering will become a poor method for averaging. */ \
  2762. /* (When reducing the image, the weighting used by a bilinear filter becomes */ \
  2763. /* arbitrary, and a simple mean is a better way to represent the source image.) */ \
  2764. /* You can think of this as a kind of mipmapping. */ \
  2765. if ((aa < 460 && aa > -460) && (cc < 460 && cc > -460)) \
  2766. {\
  2767. for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
  2768. { \
  2769. uint32 xPos = AA + BB; \
  2770. uint32 xPix = xPos >> 8; \
  2771. uint32 yPos = CC + DD; \
  2772. uint32 yPix = yPos >> 8; \
  2773. uint32 X = xPix & 0x3ff; \
  2774. uint32 Y = yPix & 0x3ff; \
  2775. uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
  2776. uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
  2777. GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
  2778. if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
  2779. { \
  2780. /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
  2781. uint32 X10 = (xPix + dir) & 0x3ff; \
  2782. uint32 Y01 = (yPix + (PPU.Mode7VFlip?-1:1)) & 0x3ff; \
  2783. uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
  2784. uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
  2785. uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
  2786. uint32 p1 = COLORFUNC; \
  2787. p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
  2788. b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
  2789. uint32 p2 = COLORFUNC; \
  2790. p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
  2791. b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
  2792. uint32 p4 = COLORFUNC; \
  2793. p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
  2794. b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
  2795. uint32 p3 = COLORFUNC; \
  2796. p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
  2797. /* Xdel, Ydel: position (in 1/32nds) between the points */ \
  2798. uint32 Xdel = (xPos >> 3) & 0x1F; \
  2799. uint32 Ydel = (yPos >> 3) & 0x1F; \
  2800. uint32 XY = (Xdel*Ydel) >> 5; \
  2801. uint32 area1 = 0x20 + XY - Xdel - Ydel; \
  2802. uint32 area2 = Xdel - XY; \
  2803. uint32 area3 = Ydel - XY; \
  2804. uint32 area4 = XY; \
  2805. if(PPU.Mode7HFlip){ \
  2806. uint32 tmp=area1; area1=area2; area2=tmp; \
  2807. tmp=area3; area3=area4; area4=tmp; \
  2808. } \
  2809. if(PPU.Mode7VFlip){ \
  2810. uint32 tmp=area1; area1=area3; area3=tmp; \
  2811. tmp=area2; area2=area4; area4=tmp; \
  2812. } \
  2813. uint32 tempColor = ((area1 * p1) + \
  2814. (area2 * p2) + \
  2815. (area3 * p3) + \
  2816. (area4 * p4)) >> 5; \
  2817. TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
  2818. *p = (FUNC) | ALPHA_BITS_MASK; \
  2819. *d = GFX.Z1; \
  2820. } \
  2821. } \
  2822. } \
  2823. else \
  2824. /* The oversampling method: get the colors at four corners of a square */ \
  2825. /* in the _displayed_ image, and average them. It's sharp and clean, but */ \
  2826. /* gives the usual huge pixels when the source image gets "close." */ \
  2827. { \
  2828. /* Find the dimensions of the square in the source image whose corners will be examined. */ \
  2829. uint32 aaDelX = aa >> 1; \
  2830. uint32 ccDelX = cc >> 1; \
  2831. uint32 bbDelY = l->MatrixB >> 1; \
  2832. uint32 ddDelY = l->MatrixD >> 1; \
  2833. /* Offset the location within the source image so that the four sampled points */ \
  2834. /* center around where the single point would otherwise have been drawn. */ \
  2835. BB -= (bbDelY >> 1); \
  2836. DD -= (ddDelY >> 1); \
  2837. AA -= (aaDelX >> 1); \
  2838. CC -= (ccDelX >> 1); \
  2839. uint32 BB10 = BB + aaDelX; \
  2840. uint32 BB01 = BB + bbDelY; \
  2841. uint32 BB11 = BB + aaDelX + bbDelY; \
  2842. uint32 DD10 = DD + ccDelX; \
  2843. uint32 DD01 = DD + ddDelY; \
  2844. uint32 DD11 = DD + ccDelX + ddDelY; \
  2845. for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
  2846. { \
  2847. uint32 X = ((AA + BB) >> 8) & 0x3ff; \
  2848. uint32 Y = ((CC + DD) >> 8) & 0x3ff; \
  2849. uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
  2850. uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
  2851. GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
  2852. if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
  2853. { \
  2854. /* X, Y, X10, Y10, etc. are the coordinates of the four pixels within the */ \
  2855. /* source image that we're going to examine. */ \
  2856. uint32 X10 = ((AA + BB10) >> 8) & 0x3ff; \
  2857. uint32 Y10 = ((CC + DD10) >> 8) & 0x3ff; \
  2858. uint32 X01 = ((AA + BB01) >> 8) & 0x3ff; \
  2859. uint32 Y01 = ((CC + DD01) >> 8) & 0x3ff; \
  2860. uint32 X11 = ((AA + BB11) >> 8) & 0x3ff; \
  2861. uint32 Y11 = ((CC + DD11) >> 8) & 0x3ff; \
  2862. uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y10 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
  2863. uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X01 >> 2) & ~1)] << 7); \
  2864. uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y11 & ~7) << 5) + ((X11 >> 2) & ~1)] << 7); \
  2865. TYPE p1 = COLORFUNC; \
  2866. b = *(TileData10 + ((Y10 & 7) << 4) + ((X10 & 7) << 1)); \
  2867. TYPE p2 = COLORFUNC; \
  2868. b = *(TileData01 + ((Y01 & 7) << 4) + ((X01 & 7) << 1)); \
  2869. TYPE p3 = COLORFUNC; \
  2870. b = *(TileData11 + ((Y11 & 7) << 4) + ((X11 & 7) << 1)); \
  2871. TYPE p4 = COLORFUNC; \
  2872. TYPE theColor = Q_INTERPOLATE(p1, p2, p3, p4); \
  2873. *p = (FUNC) | ALPHA_BITS_MASK; \
  2874. *d = GFX.Z1; \
  2875. } \
  2876. } \
  2877. } \
  2878. } \
  2879. else \
  2880. { \
  2881. for (int x = startx; x != endx; x += dir, AA += aa, CC += cc, p++, d++) \
  2882. { \
  2883. uint32 xPos = AA + BB; \
  2884. uint32 xPix = xPos >> 8; \
  2885. uint32 yPos = CC + DD; \
  2886. uint32 yPix = yPos >> 8; \
  2887. uint32 X = xPix; \
  2888. uint32 Y = yPix; \
  2889. \
  2890. \
  2891. if (((X | Y) & ~0x3ff) == 0) \
  2892. { \
  2893. uint8 *TileData = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
  2894. uint32 b = *(TileData + ((Y & 7) << 4) + ((X & 7) << 1)); \
  2895. GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
  2896. if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
  2897. { \
  2898. /* X10 and Y01 are the X and Y coordinates of the next source point over. */ \
  2899. uint32 X10 = (xPix + dir) & 0x3ff; \
  2900. uint32 Y01 = (yPix + dir) & 0x3ff; \
  2901. uint8 *TileData10 = VRAM1 + (Memory.VRAM[((Y & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
  2902. uint8 *TileData11 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X10 >> 2) & ~1)] << 7); \
  2903. uint8 *TileData01 = VRAM1 + (Memory.VRAM[((Y01 & ~7) << 5) + ((X >> 2) & ~1)] << 7); \
  2904. uint32 p1 = COLORFUNC; \
  2905. p1 = (p1 & FIRST_THIRD_COLOR_MASK) | ((p1 & SECOND_COLOR_MASK) << 16); \
  2906. b = *(TileData10 + ((Y & 7) << 4) + ((X10 & 7) << 1)); \
  2907. uint32 p2 = COLORFUNC; \
  2908. p2 = (p2 & FIRST_THIRD_COLOR_MASK) | ((p2 & SECOND_COLOR_MASK) << 16); \
  2909. b = *(TileData11 + ((Y01 & 7) << 4) + ((X10 & 7) << 1)); \
  2910. uint32 p4 = COLORFUNC; \
  2911. p4 = (p4 & FIRST_THIRD_COLOR_MASK) | ((p4 & SECOND_COLOR_MASK) << 16); \
  2912. b = *(TileData01 + ((Y01 & 7) << 4) + ((X & 7) << 1)); \
  2913. uint32 p3 = COLORFUNC; \
  2914. p3 = (p3 & FIRST_THIRD_COLOR_MASK) | ((p3 & SECOND_COLOR_MASK) << 16); \
  2915. /* Xdel, Ydel: position (in 1/32nds) between the points */ \
  2916. uint32 Xdel = (xPos >> 3) & 0x1F; \
  2917. uint32 Ydel = (yPos >> 3) & 0x1F; \
  2918. uint32 XY = (Xdel*Ydel) >> 5; \
  2919. uint32 area1 = 0x20 + XY - Xdel - Ydel; \
  2920. uint32 area2 = Xdel - XY; \
  2921. uint32 area3 = Ydel - XY; \
  2922. uint32 area4 = XY; \
  2923. uint32 tempColor = ((area1 * p1) + \
  2924. (area2 * p2) + \
  2925. (area3 * p3) + \
  2926. (area4 * p4)) >> 5; \
  2927. TYPE theColor = (tempColor & FIRST_THIRD_COLOR_MASK) | ((tempColor >> 16) & SECOND_COLOR_MASK); \
  2928. *p = (FUNC) | ALPHA_BITS_MASK; \
  2929. *d = GFX.Z1; \
  2930. } \
  2931. } \
  2932. else \
  2933. { \
  2934. if (PPU.Mode7Repeat == 3) \
  2935. { \
  2936. X = (x + HOffset) & 7; \
  2937. Y = (yy + CentreY) & 7; \
  2938. uint32 b = *(VRAM1 + ((Y & 7) << 4) + ((X & 7) << 1)); \
  2939. GFX.Z1 = Mode7Depths [(b & GFX.Mode7PriorityMask) >> 7]; \
  2940. if (GFX.Z1 > *d && (b & GFX.Mode7Mask) ) \
  2941. { \
  2942. TYPE theColor = COLORFUNC; \
  2943. *p = (FUNC) | ALPHA_BITS_MASK; \
  2944. *d = GFX.Z1; \
  2945. } \
  2946. } \
  2947. } \
  2948. } \
  2949. } \
  2950. } \
  2951. }
  2952. STATIC uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D)
  2953. {
  2954. register uint32 x = ((A >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
  2955. ((B >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
  2956. ((C >> 2) & HIGH_BITS_SHIFTED_TWO_MASK) +
  2957. ((D >> 2) & HIGH_BITS_SHIFTED_TWO_MASK);
  2958. register uint32 y = (A & TWO_LOW_BITS_MASK) +
  2959. (B & TWO_LOW_BITS_MASK) +
  2960. (C & TWO_LOW_BITS_MASK) +
  2961. (D & TWO_LOW_BITS_MASK);
  2962. y = (y>>2) & TWO_LOW_BITS_MASK;
  2963. return x+y;
  2964. }
  2965. static void DrawBGMode7Background16_i (uint8 *Screen, int bg)
  2966. {
  2967. RENDER_BACKGROUND_MODE7_i (uint16, theColor, (ScreenColors[b & GFX.Mode7Mask]));
  2968. }
  2969. static void DrawBGMode7Background16Add_i (uint8 *Screen, int bg)
  2970. {
  2971. RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
  2972. (*(d + GFX.DepthDelta) != 1 ?
  2973. (COLOR_ADD (theColor,
  2974. p [GFX.Delta])) :
  2975. (COLOR_ADD (theColor,
  2976. GFX.FixedColour))) :
  2977. theColor, (ScreenColors[b & GFX.Mode7Mask]));
  2978. }
  2979. static void DrawBGMode7Background16Add1_2_i (uint8 *Screen, int bg)
  2980. {
  2981. RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
  2982. (*(d + GFX.DepthDelta) != 1 ?
  2983. COLOR_ADD1_2 (theColor,
  2984. p [GFX.Delta]) :
  2985. COLOR_ADD (theColor,
  2986. GFX.FixedColour)) :
  2987. theColor, (ScreenColors[b & GFX.Mode7Mask]));
  2988. }
  2989. static void DrawBGMode7Background16Sub_i (uint8 *Screen, int bg)
  2990. {
  2991. RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
  2992. (*(d + GFX.DepthDelta) != 1 ?
  2993. COLOR_SUB (theColor,
  2994. p [GFX.Delta]) :
  2995. COLOR_SUB (theColor,
  2996. GFX.FixedColour)) :
  2997. theColor, (ScreenColors[b & GFX.Mode7Mask]));
  2998. }
  2999. static void DrawBGMode7Background16Sub1_2_i (uint8 *Screen, int bg)
  3000. {
  3001. RENDER_BACKGROUND_MODE7_i (uint16, *(d + GFX.DepthDelta) ?
  3002. (*(d + GFX.DepthDelta) != 1 ?
  3003. COLOR_SUB1_2 (theColor,
  3004. p [GFX.Delta]) :
  3005. COLOR_SUB (theColor,
  3006. GFX.FixedColour)) :
  3007. theColor, (ScreenColors[b & GFX.Mode7Mask]));
  3008. }
  3009. #define _BUILD_SETUP(F) \
  3010. GFX.BuildPixel = BuildPixel##F; \
  3011. GFX.BuildPixel2 = BuildPixel2##F; \
  3012. GFX.DecomposePixel = DecomposePixel##F; \
  3013. RED_LOW_BIT_MASK = RED_LOW_BIT_MASK_##F; \
  3014. GREEN_LOW_BIT_MASK = GREEN_LOW_BIT_MASK_##F; \
  3015. BLUE_LOW_BIT_MASK = BLUE_LOW_BIT_MASK_##F; \
  3016. RED_HI_BIT_MASK = RED_HI_BIT_MASK_##F; \
  3017. GREEN_HI_BIT_MASK = GREEN_HI_BIT_MASK_##F; \
  3018. BLUE_HI_BIT_MASK = BLUE_HI_BIT_MASK_##F; \
  3019. MAX_RED = MAX_RED_##F; \
  3020. MAX_GREEN = MAX_GREEN_##F; \
  3021. MAX_BLUE = MAX_BLUE_##F; \
  3022. GREEN_HI_BIT = ((MAX_GREEN_##F + 1) >> 1); \
  3023. SPARE_RGB_BIT_MASK = SPARE_RGB_BIT_MASK_##F; \
  3024. RGB_LOW_BITS_MASK = (RED_LOW_BIT_MASK_##F | \
  3025. GREEN_LOW_BIT_MASK_##F | \
  3026. BLUE_LOW_BIT_MASK_##F); \
  3027. RGB_HI_BITS_MASK = (RED_HI_BIT_MASK_##F | \
  3028. GREEN_HI_BIT_MASK_##F | \
  3029. BLUE_HI_BIT_MASK_##F); \
  3030. RGB_HI_BITS_MASKx2 = ((RED_HI_BIT_MASK_##F | \
  3031. GREEN_HI_BIT_MASK_##F | \
  3032. BLUE_HI_BIT_MASK_##F) << 1); \
  3033. RGB_REMOVE_LOW_BITS_MASK = ~RGB_LOW_BITS_MASK; \
  3034. FIRST_COLOR_MASK = FIRST_COLOR_MASK_##F; \
  3035. SECOND_COLOR_MASK = SECOND_COLOR_MASK_##F; \
  3036. THIRD_COLOR_MASK = THIRD_COLOR_MASK_##F; \
  3037. ALPHA_BITS_MASK = ALPHA_BITS_MASK_##F; \
  3038. FIRST_THIRD_COLOR_MASK = FIRST_COLOR_MASK | THIRD_COLOR_MASK; \
  3039. TWO_LOW_BITS_MASK = RGB_LOW_BITS_MASK | (RGB_LOW_BITS_MASK << 1); \
  3040. HIGH_BITS_SHIFTED_TWO_MASK = (( (FIRST_COLOR_MASK | SECOND_COLOR_MASK | THIRD_COLOR_MASK) & \
  3041. ~TWO_LOW_BITS_MASK ) >> 2);
  3042. static void RenderScreen (uint8 *Screen, bool8 sub, bool8 force_no_add, uint8 D)
  3043. {
  3044. bool8 BG0;
  3045. bool8 BG1;
  3046. bool8 BG2;
  3047. bool8 BG3;
  3048. bool8 OB;
  3049. GFX.S = Screen;
  3050. if (!sub)
  3051. {
  3052. GFX.pCurrentClip = &IPPU.Clip [0];
  3053. BG0 = ON_MAIN (0);
  3054. BG1 = ON_MAIN (1);
  3055. BG2 = ON_MAIN (2);
  3056. BG3 = ON_MAIN (3);
  3057. OB = ON_MAIN (4);
  3058. }
  3059. else
  3060. {
  3061. GFX.pCurrentClip = &IPPU.Clip [1];
  3062. BG0 = ON_SUB (0);
  3063. BG1 = ON_SUB (1);
  3064. BG2 = ON_SUB (2);
  3065. BG3 = ON_SUB (3);
  3066. OB = ON_SUB (4);
  3067. }
  3068. sub |= force_no_add;
  3069. switch (PPU.BGMode) {
  3070. case 0:
  3071. case 1:
  3072. if (OB)
  3073. {
  3074. SelectTileRenderer (sub || !SUB_OR_ADD(4));
  3075. DrawOBJS (!sub, D);
  3076. }
  3077. if (BG0)
  3078. {
  3079. SelectTileRenderer (sub || !SUB_OR_ADD(0));
  3080. DrawBackground (PPU.BGMode, 0, D + 10, D + 14);
  3081. }
  3082. if (BG1)
  3083. {
  3084. SelectTileRenderer (sub || !SUB_OR_ADD(1));
  3085. DrawBackground (PPU.BGMode, 1, D + 9, D + 13);
  3086. }
  3087. if (BG2)
  3088. {
  3089. SelectTileRenderer (sub || !SUB_OR_ADD(2));
  3090. DrawBackground (PPU.BGMode, 2, D + 3,
  3091. PPU.BG3Priority ? D + 17 : D + 6);
  3092. }
  3093. if (BG3 && PPU.BGMode == 0)
  3094. {
  3095. SelectTileRenderer (sub || !SUB_OR_ADD(3));
  3096. DrawBackground (PPU.BGMode, 3, D + 2, D + 5);
  3097. }
  3098. break;
  3099. case 2:
  3100. case 3:
  3101. case 4:
  3102. case 5:
  3103. case 6:
  3104. if (OB)
  3105. {
  3106. SelectTileRenderer (sub || !SUB_OR_ADD(4));
  3107. DrawOBJS (!sub, D);
  3108. }
  3109. if (BG0)
  3110. {
  3111. SelectTileRenderer (sub || !SUB_OR_ADD(0));
  3112. DrawBackground (PPU.BGMode, 0, D + 5, D + 13);
  3113. }
  3114. if (BG1 && PPU.BGMode != 6)
  3115. {
  3116. SelectTileRenderer (sub || !SUB_OR_ADD(1));
  3117. DrawBackground (PPU.BGMode, 1, D + 2, D + 9);
  3118. }
  3119. break;
  3120. case 7:
  3121. if (OB)
  3122. {
  3123. SelectTileRenderer (sub || !SUB_OR_ADD(4));
  3124. DrawOBJS (!sub, D);
  3125. }
  3126. if (BG0 || ((Memory.FillRAM [0x2133] & 0x40) && BG1))
  3127. {
  3128. int bg;
  3129. if ((Memory.FillRAM [0x2133] & 0x40)&&BG1)
  3130. {
  3131. GFX.Mode7Mask = 0x7f;
  3132. GFX.Mode7PriorityMask = 0x80;
  3133. Mode7Depths [0] = (BG0?5:1) + D;
  3134. Mode7Depths [1] = 9 + D;
  3135. bg = 1;
  3136. }
  3137. else
  3138. {
  3139. GFX.Mode7Mask = 0xff;
  3140. GFX.Mode7PriorityMask = 0;
  3141. Mode7Depths [0] = 5 + D;
  3142. Mode7Depths [1] = 5 + D;
  3143. bg = 0;
  3144. }
  3145. if (sub || !SUB_OR_ADD(0))
  3146. {
  3147. if (!Settings.Mode7Interpolate)
  3148. DrawBGMode7Background16 (Screen, bg);
  3149. else
  3150. DrawBGMode7Background16_i (Screen, bg);
  3151. }
  3152. else
  3153. {
  3154. if (GFX.r2131 & 0x80)
  3155. {
  3156. if (GFX.r2131 & 0x40)
  3157. {
  3158. if (!Settings.Mode7Interpolate)
  3159. DrawBGMode7Background16Sub1_2 (Screen, bg);
  3160. else
  3161. DrawBGMode7Background16Sub1_2_i (Screen, bg);
  3162. }
  3163. else
  3164. {
  3165. if (!Settings.Mode7Interpolate)
  3166. DrawBGMode7Background16Sub (Screen, bg);
  3167. else
  3168. DrawBGMode7Background16Sub_i (Screen, bg);
  3169. }
  3170. }
  3171. else
  3172. {
  3173. if (GFX.r2131 & 0x40)
  3174. {
  3175. if (!Settings.Mode7Interpolate)
  3176. DrawBGMode7Background16Add1_2 (Screen, bg);
  3177. else
  3178. DrawBGMode7Background16Add1_2_i (Screen, bg);
  3179. }
  3180. else
  3181. {
  3182. if (!Settings.Mode7Interpolate)
  3183. DrawBGMode7Background16Add (Screen, bg);
  3184. else
  3185. DrawBGMode7Background16Add_i (Screen, bg);
  3186. }
  3187. }
  3188. }
  3189. }
  3190. break;
  3191. default:
  3192. break;
  3193. }
  3194. }
  3195. #include "font.h"
  3196. void DisplayChar (uint8 *Screen, uint8 c)
  3197. {
  3198. int line = (((c & 0x7f) - 32) >> 4) * font_height;
  3199. int offset = (((c & 0x7f) - 32) & 15) * font_width;
  3200. #ifndef FOREVER_16_BIT
  3201. if (Settings.SixteenBit)
  3202. {
  3203. #endif
  3204. int h, w;
  3205. uint16 *s = (uint16 *) Screen;
  3206. for (h = 0; h < font_height; h++, line++,
  3207. s += GFX.PPL - font_width)
  3208. {
  3209. for (w = 0; w < font_width; w++, s++)
  3210. {
  3211. uint8 p = font [line][offset + w];
  3212. if (p == '#')
  3213. {
  3214. /*
  3215. if(Memory.Hacked)
  3216. *s= BUILD_PIXEL(31,0,0);
  3217. else if(Memory.Iffy)
  3218. *s= BUILD_PIXEL(31,31,0);
  3219. else if(Memory.Iformat==1)
  3220. *s= BUILD_PIXEL(0,31,0);
  3221. else if(Memory.Iformat==2)
  3222. *s= BUILD_PIXEL(0,31,31);
  3223. else *s = 0xffff;
  3224. */
  3225. *s=Settings.DisplayColor;
  3226. }
  3227. else
  3228. if (p == '.')
  3229. *s = BLACK;
  3230. }
  3231. }
  3232. #ifndef FOREVER_16_BIT
  3233. }
  3234. else
  3235. {
  3236. int h, w;
  3237. uint8 *s = Screen;
  3238. for (h = 0; h < font_height; h++, line++,
  3239. s += GFX.PPL - font_width)
  3240. {
  3241. for (w = 0; w < font_width; w++, s++)
  3242. {
  3243. uint8 p = font [line][offset + w];
  3244. if (p == '#')
  3245. *s = 255;
  3246. else
  3247. if (p == '.')
  3248. *s = BLACK;
  3249. }
  3250. }
  3251. }
  3252. #endif
  3253. }
  3254. static void S9xDisplayFrameRate ()
  3255. {
  3256. uint8 *Screen = GFX.Screen + 2 +
  3257. (IPPU.RenderedScreenHeight - font_height - 1) * GFX.Pitch2;
  3258. char string [10];
  3259. int len = 5;
  3260. sprintf (string, "%02d/%02d", IPPU.DisplayedRenderedFrameCount,
  3261. (int) Memory.ROMFramesPerSecond);
  3262. int i;
  3263. for (i = 0; i < len; i++)
  3264. {
  3265. DisplayChar (Screen, string [i]);
  3266. #ifndef FOREVER_16_BIT
  3267. Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) :
  3268. (font_width - 1);
  3269. #else
  3270. Screen += (font_width - 1) * sizeof (uint16);
  3271. #endif
  3272. }
  3273. }
  3274. static void S9xDisplayString (const char *string)
  3275. {
  3276. uint8 *Screen = GFX.Screen + 2 +
  3277. (IPPU.RenderedScreenHeight - font_height * 5) * GFX.Pitch2;
  3278. int len = strlen (string);
  3279. int max_chars = IPPU.RenderedScreenWidth / (font_width - 1);
  3280. int char_count = 0;
  3281. int i;
  3282. for (i = 0; i < len; i++, char_count++)
  3283. {
  3284. if (char_count >= max_chars || string [i] < 32)
  3285. {
  3286. #ifndef FOREVER_16_BIT
  3287. Screen -= Settings.SixteenBit ?
  3288. (font_width - 1) * sizeof (uint16) * max_chars :
  3289. (font_width - 1) * max_chars;
  3290. #else
  3291. Screen -= (font_width - 1) * max_chars * sizeof (uint16);
  3292. #endif
  3293. Screen += font_height * GFX.Pitch;
  3294. if (Screen >= GFX.Screen + GFX.Pitch * IPPU.RenderedScreenHeight)
  3295. break;
  3296. char_count -= max_chars;
  3297. }
  3298. if (string [i] < 32)
  3299. continue;
  3300. DisplayChar (Screen, string [i]);
  3301. #ifndef FOREVER_16_BIT
  3302. Screen += Settings.SixteenBit ? (font_width - 1) * sizeof (uint16) :
  3303. (font_width - 1);
  3304. #else
  3305. Screen += (font_width - 1) * sizeof (uint16);
  3306. #endif
  3307. }
  3308. }
  3309. void S9xUpdateScreen ()
  3310. {
  3311. int32 x2 = 1;
  3312. GFX.S = GFX.Screen;
  3313. GFX.r2131 = Memory.FillRAM [0x2131];
  3314. GFX.r212c = Memory.FillRAM [0x212c];
  3315. GFX.r212d = Memory.FillRAM [0x212d];
  3316. GFX.r2130 = Memory.FillRAM [0x2130];
  3317. #ifdef JP_FIX
  3318. GFX.Pseudo = (Memory.FillRAM [0x2133] & 8) != 0 &&
  3319. (GFX.r212c & 15) != (GFX.r212d & 15) &&
  3320. (GFX.r2131 == 0x3f);
  3321. #else
  3322. GFX.Pseudo = (Memory.FillRAM [0x2133] & 8) != 0 &&
  3323. (GFX.r212c & 15) != (GFX.r212d & 15) &&
  3324. (GFX.r2131 & 0x3f) == 0;
  3325. #endif
  3326. if (IPPU.OBJChanged)
  3327. S9xSetupOBJ ();
  3328. if (PPU.RecomputeClipWindows)
  3329. {
  3330. ComputeClipWindows ();
  3331. PPU.RecomputeClipWindows = FALSE;
  3332. }
  3333. GFX.StartY = IPPU.PreviousLine;
  3334. if ((GFX.EndY = IPPU.CurrentLine - 1) >= PPU.ScreenHeight)
  3335. GFX.EndY = PPU.ScreenHeight - 1;
  3336. // XXX: Check ForceBlank? Or anything else?
  3337. PPU.RangeTimeOver |= GFX.OBJLines[GFX.EndY].RTOFlags;
  3338. uint32 starty = GFX.StartY;
  3339. uint32 endy = GFX.EndY;
  3340. if (Settings.SupportHiRes &&
  3341. (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.Interlace || IPPU.DoubleHeightPixels))
  3342. {
  3343. if (PPU.BGMode == 5 || PPU.BGMode == 6|| IPPU.Interlace)
  3344. {
  3345. IPPU.RenderedScreenWidth = 512;
  3346. x2 = 2;
  3347. }
  3348. if (IPPU.DoubleHeightPixels)
  3349. {
  3350. starty = GFX.StartY * 2;
  3351. endy = GFX.EndY * 2 + 1;
  3352. }
  3353. if ((PPU.BGMode == 5 || PPU.BGMode == 6) && !IPPU.DoubleWidthPixels)
  3354. {
  3355. // The game has switched from lo-res to hi-res mode part way down
  3356. // the screen. Scale any existing lo-res pixels on screen
  3357. #ifndef FOREVER_16_BIT
  3358. if (Settings.SixteenBit)
  3359. {
  3360. #endif
  3361. for (register uint32 y = 0; y < starty; y++)
  3362. {
  3363. register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + 255;
  3364. register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + 510;
  3365. for (register int x = 255; x >= 0; x--, p--, q -= 2)
  3366. *q = *(q + 1) = *p;
  3367. }
  3368. #ifndef FOREVER_16_BIT
  3369. }
  3370. else
  3371. {
  3372. for (register uint32 y = 0; y < starty; y++)
  3373. {
  3374. register uint8 *p = GFX.Screen + y * GFX.Pitch2 + 255;
  3375. register uint8 *q = GFX.Screen + y * GFX.Pitch2 + 510;
  3376. for (register int x = 255; x >= 0; x--, p--, q -= 2)
  3377. *q = *(q + 1) = *p;
  3378. }
  3379. }
  3380. #endif
  3381. IPPU.DoubleWidthPixels = TRUE;
  3382. IPPU.HalfWidthPixels = FALSE;
  3383. }
  3384. // BJ: And we have to change the height if Interlace gets set,
  3385. // too.
  3386. if (IPPU.Interlace && !IPPU.DoubleHeightPixels)
  3387. {
  3388. starty = GFX.StartY * 2;
  3389. endy = GFX.EndY * 2 + 1;
  3390. IPPU.RenderedScreenHeight = PPU.ScreenHeight << 1;
  3391. IPPU.DoubleHeightPixels = TRUE;
  3392. GFX.Pitch2 = GFX.RealPitch;
  3393. GFX.Pitch = GFX.RealPitch * 2;
  3394. #ifndef FOREVER_16_BIT
  3395. if (Settings.SixteenBit)
  3396. #endif
  3397. GFX.PPL = GFX.PPLx2 = GFX.RealPitch;
  3398. #ifndef FOREVER_16_BIT
  3399. else
  3400. GFX.PPL = GFX.PPLx2 = GFX.RealPitch << 1;
  3401. #endif
  3402. // The game has switched from non-interlaced to interlaced mode
  3403. // part way down the screen. Scale everything.
  3404. for (register int32 y = (int32) GFX.StartY - 1; y >= 0; y--)
  3405. {
  3406. // memmove converted: Same malloc, different addresses, and identical addresses at line 0 [Neb]
  3407. // DS2 DMA notes: This code path is unused [Neb]
  3408. memcpy (GFX.Screen + y * 2 * GFX.Pitch2,
  3409. GFX.Screen + y * GFX.Pitch2,
  3410. GFX.Pitch2);
  3411. // memmove converted: Same malloc, different addresses [Neb]
  3412. memcpy (GFX.Screen + (y * 2 + 1) * GFX.Pitch2,
  3413. GFX.Screen + y * GFX.Pitch2,
  3414. GFX.Pitch2);
  3415. }
  3416. }
  3417. }
  3418. else if (!Settings.SupportHiRes)
  3419. {
  3420. if (PPU.BGMode == 5 || PPU.BGMode == 6 || IPPU.Interlace)
  3421. {
  3422. if (!IPPU.HalfWidthPixels)
  3423. {
  3424. // The game has switched from lo-res to hi-res mode part way down
  3425. // the screen. Hi-res pixels must now be drawn at half width.
  3426. IPPU.HalfWidthPixels = TRUE;
  3427. }
  3428. }
  3429. else
  3430. {
  3431. if (IPPU.HalfWidthPixels)
  3432. {
  3433. // The game has switched from hi-res to lo-res mode part way down
  3434. // the screen. Lo-res pixels must now be drawn at FULL width.
  3435. IPPU.HalfWidthPixels = FALSE;
  3436. }
  3437. }
  3438. }
  3439. uint32 black = BLACK | (BLACK << 16);
  3440. if (Settings.Transparency
  3441. #ifndef FOREVER_16_BIT
  3442. && Settings.SixteenBit
  3443. #endif
  3444. )
  3445. {
  3446. if (GFX.Pseudo)
  3447. {
  3448. GFX.r2131 = 0x5f;
  3449. GFX.r212c &= (Memory.FillRAM [0x212d] | 0xf0);
  3450. GFX.r212d |= (Memory.FillRAM [0x212c] & 0x0f);
  3451. GFX.r2130 |= 2;
  3452. }
  3453. if (!PPU.ForcedBlanking && ADD_OR_SUB_ON_ANYTHING &&
  3454. (GFX.r2130 & 0x30) != 0x30 &&
  3455. !((GFX.r2130 & 0x30) == 0x10 && IPPU.Clip[1].Count[5] == 0))
  3456. {
  3457. struct ClipData *pClip;
  3458. GFX.FixedColour = BUILD_PIXEL (IPPU.XB [PPU.FixedColourRed],
  3459. IPPU.XB [PPU.FixedColourGreen],
  3460. IPPU.XB [PPU.FixedColourBlue]);
  3461. // Clear the z-buffer, marking areas 'covered' by the fixed
  3462. // colour as depth 1.
  3463. pClip = &IPPU.Clip [1];
  3464. // Clear the z-buffer
  3465. if (pClip->Count [5])
  3466. {
  3467. // Colour window enabled.
  3468. for (uint32 y = starty; y <= endy; y++)
  3469. {
  3470. ZeroMemory (GFX.SubZBuffer + y * GFX.ZPitch, IPPU.RenderedScreenWidth);
  3471. ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch, IPPU.RenderedScreenWidth);
  3472. if (IPPU.Clip [0].Count [5])
  3473. {
  3474. uint32 *p = (uint32 *) (GFX.SubScreen + y * GFX.Pitch2);
  3475. uint32 *q = (uint32 *) ((uint16 *) p + IPPU.RenderedScreenWidth);
  3476. while (p < q)
  3477. *p++ = black;
  3478. }
  3479. for (uint32 c = 0; c < pClip->Count [5]; c++)
  3480. {
  3481. if (pClip->Right [c][5] > pClip->Left [c][5])
  3482. {
  3483. memset (GFX.SubZBuffer + y * GFX.ZPitch + pClip->Left [c][5] * x2,
  3484. 1, (pClip->Right [c][5] - pClip->Left [c][5]) * x2);
  3485. if (IPPU.Clip [0].Count [5])
  3486. {
  3487. // Blast, have to clear the sub-screen to the fixed-colour
  3488. // because there is a colour window in effect clipping
  3489. // the main screen that will allow the sub-screen
  3490. // 'underneath' to show through.
  3491. uint16 *p = (uint16 *) (GFX.SubScreen + y * GFX.Pitch2);
  3492. uint16 *q = p + pClip->Right [c][5] * x2;
  3493. p += pClip->Left [c][5] * x2;
  3494. while (p < q)
  3495. *p++ = (uint16) GFX.FixedColour;
  3496. }
  3497. }
  3498. }
  3499. }
  3500. }
  3501. else
  3502. {
  3503. for (uint32 y = starty; y <= endy; y++)
  3504. {
  3505. ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch, IPPU.RenderedScreenWidth);
  3506. memset (GFX.SubZBuffer + y * GFX.ZPitch, 1, IPPU.RenderedScreenWidth);
  3507. if (IPPU.Clip [0].Count [5])
  3508. {
  3509. // Blast, have to clear the sub-screen to the fixed-colour
  3510. // because there is a colour window in effect clipping
  3511. // the main screen that will allow the sub-screen
  3512. // 'underneath' to show through.
  3513. uint32 b = GFX.FixedColour | (GFX.FixedColour << 16);
  3514. uint32 *p = (uint32 *) (GFX.SubScreen + y * GFX.Pitch2);
  3515. uint32 *q = (uint32 *) ((uint16 *) p + IPPU.RenderedScreenWidth);
  3516. while (p < q)
  3517. *p++ = b;
  3518. }
  3519. }
  3520. }
  3521. if (ANYTHING_ON_SUB)
  3522. {
  3523. GFX.DB = GFX.SubZBuffer;
  3524. RenderScreen (GFX.SubScreen, TRUE, TRUE, SUB_SCREEN_DEPTH);
  3525. }
  3526. if (IPPU.Clip [0].Count [5])
  3527. {
  3528. for (uint32 y = starty; y <= endy; y++)
  3529. {
  3530. register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
  3531. register uint8 *d = GFX.SubZBuffer + y * GFX.ZPitch;
  3532. register uint8 *e = d + IPPU.RenderedScreenWidth;
  3533. while (d < e)
  3534. {
  3535. if (*d > 1)
  3536. *p = *(p + GFX.Delta);
  3537. else
  3538. *p = BLACK;
  3539. d++;
  3540. p++;
  3541. }
  3542. }
  3543. }
  3544. GFX.DB = GFX.ZBuffer;
  3545. RenderScreen (GFX.Screen, FALSE, FALSE, MAIN_SCREEN_DEPTH);
  3546. if (SUB_OR_ADD(5))
  3547. {
  3548. uint32 back = IPPU.ScreenColors [0];
  3549. uint32 Left = 0;
  3550. uint32 Right = 256;
  3551. uint32 Count;
  3552. pClip = &IPPU.Clip [0];
  3553. for (uint32 y = starty; y <= endy; y++)
  3554. {
  3555. if (!(Count = pClip->Count [5]))
  3556. {
  3557. Left = 0;
  3558. Right = 256 * x2;
  3559. Count = 1;
  3560. }
  3561. for (uint32 b = 0; b < Count; b++)
  3562. {
  3563. if (pClip->Count [5])
  3564. {
  3565. Left = pClip->Left [b][5] * x2;
  3566. Right = pClip->Right [b][5] * x2;
  3567. if (Right <= Left)
  3568. continue;
  3569. }
  3570. if (GFX.r2131 & 0x80)
  3571. {
  3572. if (GFX.r2131 & 0x40)
  3573. {
  3574. // Subtract, halving the result.
  3575. register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
  3576. register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
  3577. register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
  3578. register uint8 *e = d + Right;
  3579. uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
  3580. d += Left;
  3581. while (d < e)
  3582. {
  3583. if (*d == 0)
  3584. {
  3585. if (*s)
  3586. {
  3587. if (*s != 1)
  3588. *p = COLOR_SUB1_2 (back, *(p + GFX.Delta));
  3589. else
  3590. *p = back_fixed;
  3591. }
  3592. else
  3593. *p = (uint16) back;
  3594. }
  3595. d++;
  3596. p++;
  3597. s++;
  3598. }
  3599. }
  3600. else
  3601. {
  3602. // Subtract
  3603. register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
  3604. register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
  3605. register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
  3606. register uint8 *e = d + Right;
  3607. uint16 back_fixed = COLOR_SUB (back, GFX.FixedColour);
  3608. d += Left;
  3609. while (d < e)
  3610. {
  3611. if (*d == 0)
  3612. {
  3613. if (*s)
  3614. {
  3615. if (*s != 1)
  3616. *p = COLOR_SUB (back, *(p + GFX.Delta));
  3617. else
  3618. *p = back_fixed;
  3619. }
  3620. else
  3621. *p = (uint16) back;
  3622. }
  3623. d++;
  3624. p++;
  3625. s++;
  3626. }
  3627. }
  3628. }
  3629. else if (GFX.r2131 & 0x40)
  3630. {
  3631. register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
  3632. register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
  3633. register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
  3634. register uint8 *e = d + Right;
  3635. uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
  3636. d += Left;
  3637. while (d < e)
  3638. {
  3639. if (*d == 0)
  3640. {
  3641. if (*s)
  3642. {
  3643. if (*s != 1)
  3644. *p = COLOR_ADD1_2 (back, *(p + GFX.Delta));
  3645. else
  3646. *p = back_fixed;
  3647. }
  3648. else
  3649. *p = (uint16) back;
  3650. }
  3651. d++;
  3652. p++;
  3653. s++;
  3654. }
  3655. }
  3656. else if (back != 0)
  3657. {
  3658. register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
  3659. register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
  3660. register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
  3661. register uint8 *e = d + Right;
  3662. uint16 back_fixed = COLOR_ADD (back, GFX.FixedColour);
  3663. d += Left;
  3664. while (d < e)
  3665. {
  3666. if (*d == 0)
  3667. {
  3668. if (*s)
  3669. {
  3670. if (*s != 1)
  3671. *p = COLOR_ADD (back, *(p + GFX.Delta));
  3672. else
  3673. *p = back_fixed;
  3674. }
  3675. else
  3676. *p = (uint16) back;
  3677. }
  3678. d++;
  3679. p++;
  3680. s++;
  3681. }
  3682. }
  3683. else
  3684. {
  3685. if (!pClip->Count [5])
  3686. {
  3687. // The backdrop has not been cleared yet - so
  3688. // copy the sub-screen to the main screen
  3689. // or fill it with the back-drop colour if the
  3690. // sub-screen is clear.
  3691. register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
  3692. register uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
  3693. register uint8 *s = GFX.SubZBuffer + y * GFX.ZPitch + Left;
  3694. register uint8 *e = d + Right;
  3695. d += Left;
  3696. while (d < e)
  3697. {
  3698. if (*d == 0)
  3699. {
  3700. if (*s)
  3701. {
  3702. if (*s != 1)
  3703. *p = *(p + GFX.Delta);
  3704. else
  3705. *p = GFX.FixedColour;
  3706. }
  3707. else
  3708. *p = (uint16) back;
  3709. }
  3710. d++;
  3711. p++;
  3712. s++;
  3713. }
  3714. }
  3715. }
  3716. }
  3717. }
  3718. } // --if (SUB_OR_ADD(5))
  3719. else
  3720. {
  3721. // Subscreen not being added to back
  3722. uint32 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
  3723. pClip = &IPPU.Clip [0];
  3724. if (pClip->Count [5])
  3725. {
  3726. for (uint32 y = starty; y <= endy; y++)
  3727. {
  3728. for (uint32 b = 0; b < pClip->Count [5]; b++)
  3729. {
  3730. uint32 Left = pClip->Left [b][5] * x2;
  3731. uint32 Right = pClip->Right [b][5] * x2;
  3732. uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + Left;
  3733. uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
  3734. uint8 *e = d + Right;
  3735. d += Left;
  3736. while (d < e)
  3737. {
  3738. if (*d == 0)
  3739. *p = (int16) back;
  3740. d++;
  3741. p++;
  3742. }
  3743. }
  3744. }
  3745. }
  3746. else
  3747. {
  3748. for (uint32 y = starty; y <= endy; y++)
  3749. {
  3750. uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
  3751. uint8 *d = GFX.ZBuffer + y * GFX.ZPitch;
  3752. uint8 *e = d + 256 * x2;
  3753. while (d < e)
  3754. {
  3755. if (*d == 0)
  3756. *p = (int16) back;
  3757. d++;
  3758. p++;
  3759. }
  3760. }
  3761. }
  3762. }
  3763. } //force blanking
  3764. else
  3765. {
  3766. // 16bit and transparency but currently no transparency effects in
  3767. // operation.
  3768. uint32 back = IPPU.ScreenColors [0] | (IPPU.ScreenColors [0] << 16);
  3769. if (PPU.ForcedBlanking)
  3770. back = black;
  3771. if (IPPU.Clip [0].Count[5])
  3772. {
  3773. for (uint32 y = starty; y <= endy; y++)
  3774. {
  3775. uint32 *p = (uint32 *) (GFX.Screen + y * GFX.Pitch2);
  3776. uint32 *q = (uint32 *) ((uint16 *) p + IPPU.RenderedScreenWidth);
  3777. while (p < q)
  3778. *p++ = black;
  3779. for (uint32 c = 0; c < IPPU.Clip [0].Count [5]; c++)
  3780. {
  3781. if (IPPU.Clip [0].Right [c][5] > IPPU.Clip [0].Left [c][5])
  3782. {
  3783. uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2);
  3784. uint16 *q = p + IPPU.Clip [0].Right [c][5] * x2;
  3785. p += IPPU.Clip [0].Left [c][5] * x2;
  3786. while (p < q)
  3787. *p++ = (uint16) back;
  3788. }
  3789. }
  3790. }
  3791. }
  3792. else
  3793. {
  3794. for (uint32 y = starty; y <= endy; y++)
  3795. {
  3796. uint32 *p = (uint32 *) (GFX.Screen + y * GFX.Pitch2);
  3797. uint32 *q = (uint32 *) ((uint16 *) p + IPPU.RenderedScreenWidth);
  3798. while (p < q)
  3799. *p++ = back;
  3800. }
  3801. }
  3802. if (!PPU.ForcedBlanking)
  3803. {
  3804. for (uint32 y = starty; y <= endy; y++)
  3805. {
  3806. ZeroMemory (GFX.ZBuffer + y * GFX.ZPitch, IPPU.RenderedScreenWidth);
  3807. }
  3808. GFX.DB = GFX.ZBuffer;
  3809. RenderScreen (GFX.Screen, FALSE, TRUE, SUB_SCREEN_DEPTH);
  3810. }
  3811. }
  3812. }
  3813. else
  3814. {
  3815. }
  3816. if (Settings.SupportHiRes)
  3817. {
  3818. if (PPU.BGMode != 5 && PPU.BGMode != 6 && IPPU.DoubleWidthPixels)
  3819. {
  3820. // Mixure of background modes used on screen - scale width
  3821. // of all non-mode 5 and 6 pixels.
  3822. #ifndef FOREVER_16_BIT
  3823. if (Settings.SixteenBit)
  3824. {
  3825. #endif
  3826. for (register uint32 y = starty; y <= endy; y++)
  3827. {
  3828. register uint16 *p = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + 255;
  3829. register uint16 *q = (uint16 *) (GFX.Screen + y * GFX.Pitch2) + 510;
  3830. for (register int x = 255; x >= 0; x--, p--, q -= 2)
  3831. *q = *(q + 1) = *p;
  3832. }
  3833. #ifndef FOREVER_16_BIT
  3834. }
  3835. else
  3836. {
  3837. for (register uint32 y = starty; y <= endy; y++)
  3838. {
  3839. register uint8 *p = GFX.Screen + y * GFX.Pitch2 + 255;
  3840. register uint8 *q = GFX.Screen + y * GFX.Pitch2 + 510;
  3841. for (register int x = 255; x >= 0; x--, p--, q -= 2)
  3842. *q = *(q + 1) = *p;
  3843. }
  3844. }
  3845. #endif
  3846. }
  3847. // Double the height of the pixels just drawn
  3848. FIX_INTERLACE(GFX.Screen, FALSE, GFX.ZBuffer);
  3849. }
  3850. IPPU.PreviousLine = IPPU.CurrentLine;
  3851. }