1/*****************************************************************************\
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3 This file is licensed under the Snes9x License.
4 For further information, consult the LICENSE file in the root directory.
5\*****************************************************************************/
6
7#include "tileimpl.h"
8
9using namespace TileImpl;
10
11namespace {
12
13 uint32 pixbit[8][16];
14 uint8 hrbit_odd[256];
15 uint8 hrbit_even[256];
16
17 // Here are the tile converters, selected by S9xSelectTileConverter().
18 // Really, except for the definition of DOBIT and the number of times it is called, they're all the same.
19
20 #define DOBIT(n, i) \
21 if ((pix = *(tp + (n)))) \
22 { \
23 p1 |= pixbit[(i)][pix >> 4]; \
24 p2 |= pixbit[(i)][pix & 0xf]; \
25 }
26
27 uint8 ConvertTile2 (uint8 *pCache, uint32 TileAddr, uint32)
28 {
29 uint8 *tp = &Memory.VRAM[TileAddr];
30 uint32 *p = (uint32 *) pCache;
31 uint32 non_zero = 0;
32 uint8 line;
33
34 for (line = 8; line != 0; line--, tp += 2)
35 {
36 uint32 p1 = 0;
37 uint32 p2 = 0;
38 uint8 pix;
39
40 DOBIT( 0, 0);
41 DOBIT( 1, 1);
42 *p++ = p1;
43 *p++ = p2;
44 non_zero |= p1 | p2;
45 }
46
47 return (non_zero ? TRUE : BLANK_TILE);
48 }
49
50 uint8 ConvertTile4 (uint8 *pCache, uint32 TileAddr, uint32)
51 {
52 uint8 *tp = &Memory.VRAM[TileAddr];
53 uint32 *p = (uint32 *) pCache;
54 uint32 non_zero = 0;
55 uint8 line;
56
57 for (line = 8; line != 0; line--, tp += 2)
58 {
59 uint32 p1 = 0;
60 uint32 p2 = 0;
61 uint8 pix;
62
63 DOBIT( 0, 0);
64 DOBIT( 1, 1);
65 DOBIT(16, 2);
66 DOBIT(17, 3);
67 *p++ = p1;
68 *p++ = p2;
69 non_zero |= p1 | p2;
70 }
71
72 return (non_zero ? TRUE : BLANK_TILE);
73 }
74
75 uint8 ConvertTile8 (uint8 *pCache, uint32 TileAddr, uint32)
76 {
77 uint8 *tp = &Memory.VRAM[TileAddr];
78 uint32 *p = (uint32 *) pCache;
79 uint32 non_zero = 0;
80 uint8 line;
81
82 for (line = 8; line != 0; line--, tp += 2)
83 {
84 uint32 p1 = 0;
85 uint32 p2 = 0;
86 uint8 pix;
87
88 DOBIT( 0, 0);
89 DOBIT( 1, 1);
90 DOBIT(16, 2);
91 DOBIT(17, 3);
92 DOBIT(32, 4);
93 DOBIT(33, 5);
94 DOBIT(48, 6);
95 DOBIT(49, 7);
96 *p++ = p1;
97 *p++ = p2;
98 non_zero |= p1 | p2;
99 }
100
101 return (non_zero ? TRUE : BLANK_TILE);
102 }
103
104 #undef DOBIT
105
106 #define DOBIT(n, i) \
107 if ((pix = hrbit_odd[*(tp1 + (n))])) \
108 p1 |= pixbit[(i)][pix]; \
109 if ((pix = hrbit_odd[*(tp2 + (n))])) \
110 p2 |= pixbit[(i)][pix];
111
112 uint8 ConvertTile2h_odd (uint8 *pCache, uint32 TileAddr, uint32 Tile)
113 {
114 uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2;
115 uint32 *p = (uint32 *) pCache;
116 uint32 non_zero = 0;
117 uint8 line;
118
119 if (Tile == 0x3ff)
120 tp2 = tp1 - (0x3ff << 4);
121 else
122 tp2 = tp1 + (1 << 4);
123
124 for (line = 8; line != 0; line--, tp1 += 2, tp2 += 2)
125 {
126 uint32 p1 = 0;
127 uint32 p2 = 0;
128 uint8 pix;
129
130 DOBIT( 0, 0);
131 DOBIT( 1, 1);
132 *p++ = p1;
133 *p++ = p2;
134 non_zero |= p1 | p2;
135 }
136
137 return (non_zero ? TRUE : BLANK_TILE);
138 }
139
140 uint8 ConvertTile4h_odd (uint8 *pCache, uint32 TileAddr, uint32 Tile)
141 {
142 uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2;
143 uint32 *p = (uint32 *) pCache;
144 uint32 non_zero = 0;
145 uint8 line;
146
147 if (Tile == 0x3ff)
148 tp2 = tp1 - (0x3ff << 5);
149 else
150 tp2 = tp1 + (1 << 5);
151
152 for (line = 8; line != 0; line--, tp1 += 2, tp2 += 2)
153 {
154 uint32 p1 = 0;
155 uint32 p2 = 0;
156 uint8 pix;
157
158 DOBIT( 0, 0);
159 DOBIT( 1, 1);
160 DOBIT(16, 2);
161 DOBIT(17, 3);
162 *p++ = p1;
163 *p++ = p2;
164 non_zero |= p1 | p2;
165 }
166
167 return (non_zero ? TRUE : BLANK_TILE);
168 }
169
170 #undef DOBIT
171
172 #define DOBIT(n, i) \
173 if ((pix = hrbit_even[*(tp1 + (n))])) \
174 p1 |= pixbit[(i)][pix]; \
175 if ((pix = hrbit_even[*(tp2 + (n))])) \
176 p2 |= pixbit[(i)][pix];
177
178 uint8 ConvertTile2h_even (uint8 *pCache, uint32 TileAddr, uint32 Tile)
179 {
180 uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2;
181 uint32 *p = (uint32 *) pCache;
182 uint32 non_zero = 0;
183 uint8 line;
184
185 if (Tile == 0x3ff)
186 tp2 = tp1 - (0x3ff << 4);
187 else
188 tp2 = tp1 + (1 << 4);
189
190 for (line = 8; line != 0; line--, tp1 += 2, tp2 += 2)
191 {
192 uint32 p1 = 0;
193 uint32 p2 = 0;
194 uint8 pix;
195
196 DOBIT( 0, 0);
197 DOBIT( 1, 1);
198 *p++ = p1;
199 *p++ = p2;
200 non_zero |= p1 | p2;
201 }
202
203 return (non_zero ? TRUE : BLANK_TILE);
204 }
205
206 uint8 ConvertTile4h_even (uint8 *pCache, uint32 TileAddr, uint32 Tile)
207 {
208 uint8 *tp1 = &Memory.VRAM[TileAddr], *tp2;
209 uint32 *p = (uint32 *) pCache;
210 uint32 non_zero = 0;
211 uint8 line;
212
213 if (Tile == 0x3ff)
214 tp2 = tp1 - (0x3ff << 5);
215 else
216 tp2 = tp1 + (1 << 5);
217
218 for (line = 8; line != 0; line--, tp1 += 2, tp2 += 2)
219 {
220 uint32 p1 = 0;
221 uint32 p2 = 0;
222 uint8 pix;
223
224 DOBIT( 0, 0);
225 DOBIT( 1, 1);
226 DOBIT(16, 2);
227 DOBIT(17, 3);
228 *p++ = p1;
229 *p++ = p2;
230 non_zero |= p1 | p2;
231 }
232
233 return (non_zero ? TRUE : BLANK_TILE);
234 }
235
236 #undef DOBIT
237
238} // anonymous namespace
239
240void S9xInitTileRenderer (void)
241{
242 int i;
243
244 for (i = 0; i < 16; i++)
245 {
246 uint32 b = 0;
247
248 #ifdef LSB_FIRST
249 if (i & 8)
250 b |= 1;
251 if (i & 4)
252 b |= 1 << 8;
253 if (i & 2)
254 b |= 1 << 16;
255 if (i & 1)
256 b |= 1 << 24;
257 #else
258 if (i & 8)
259 b |= 1 << 24;
260 if (i & 4)
261 b |= 1 << 16;
262 if (i & 2)
263 b |= 1 << 8;
264 if (i & 1)
265 b |= 1;
266 #endif
267
268 for (uint8 bitshift = 0; bitshift < 8; bitshift++)
269 pixbit[bitshift][i] = b << bitshift;
270 }
271
272 for (i = 0; i < 256; i++)
273 {
274 uint8 m = 0;
275 uint8 s = 0;
276
277 if (i & 0x80)
278 s |= 8;
279 if (i & 0x40)
280 m |= 8;
281 if (i & 0x20)
282 s |= 4;
283 if (i & 0x10)
284 m |= 4;
285 if (i & 0x08)
286 s |= 2;
287 if (i & 0x04)
288 m |= 2;
289 if (i & 0x02)
290 s |= 1;
291 if (i & 0x01)
292 m |= 1;
293
294 hrbit_odd[i] = m;
295 hrbit_even[i] = s;
296 }
297}
298
299// Functions to select which converter and renderer to use.
300
301void S9xSelectTileRenderers (int BGMode, bool8 sub, bool8 obj)
302{
303 void (**DT) (uint32, uint32, uint32, uint32);
304 void (**DCT) (uint32, uint32, uint32, uint32, uint32, uint32);
305 void (**DMP) (uint32, uint32, uint32, uint32, uint32, uint32);
306 void (**DB) (uint32, uint32, uint32);
307 void (**DM7BG1) (uint32, uint32, int);
308 void (**DM7BG2) (uint32, uint32, int);
309 bool8 M7M1, M7M2;
310
311 M7M1 = PPU.BGMosaic[0] && PPU.Mosaic > 1;
312 M7M2 = PPU.BGMosaic[1] && PPU.Mosaic > 1;
313
314 bool8 interlace = obj ? FALSE : IPPU.Interlace;
315 bool8 hires = !sub && (BGMode == 5 || BGMode == 6 || IPPU.PseudoHires);
316
317 if (!IPPU.DoubleWidthPixels) // normal width
318 {
319 DT = Renderers<DrawTile16, Normal1x1>::Functions;
320 DCT = Renderers<DrawClippedTile16, Normal1x1>::Functions;
321 DMP = Renderers<DrawMosaicPixel16, Normal1x1>::Functions;
322 DB = Renderers<DrawBackdrop16, Normal1x1>::Functions;
323 DM7BG1 = M7M1 ? Renderers<DrawMode7MosaicBG1, Normal1x1>::Functions : Renderers<DrawMode7BG1, Normal1x1>::Functions;
324 DM7BG2 = M7M2 ? Renderers<DrawMode7MosaicBG2, Normal1x1>::Functions : Renderers<DrawMode7BG2, Normal1x1>::Functions;
325 GFX.LinesPerTile = 8;
326 }
327 else if(hires) // hires double width
328 {
329 if (interlace)
330 {
331 DT = Renderers<DrawTile16, HiresInterlace>::Functions;
332 DCT = Renderers<DrawClippedTile16, HiresInterlace>::Functions;
333 DMP = Renderers<DrawMosaicPixel16, HiresInterlace>::Functions;
334 DB = Renderers<DrawBackdrop16, Hires>::Functions;
335 DM7BG1 = M7M1 ? Renderers<DrawMode7MosaicBG1, Hires>::Functions : Renderers<DrawMode7BG1, Hires>::Functions;
336 DM7BG2 = M7M2 ? Renderers<DrawMode7MosaicBG2, Hires>::Functions : Renderers<DrawMode7BG2, Hires>::Functions;
337 GFX.LinesPerTile = 4;
338 }
339 else
340 {
341 DT = Renderers<DrawTile16, Hires>::Functions;
342 DCT = Renderers<DrawClippedTile16, Hires>::Functions;
343 DMP = Renderers<DrawMosaicPixel16, Hires>::Functions;
344 DB = Renderers<DrawBackdrop16, Hires>::Functions;
345 DM7BG1 = M7M1 ? Renderers<DrawMode7MosaicBG1, Hires>::Functions : Renderers<DrawMode7BG1, Hires>::Functions;
346 DM7BG2 = M7M2 ? Renderers<DrawMode7MosaicBG2, Hires>::Functions : Renderers<DrawMode7BG2, Hires>::Functions;
347 GFX.LinesPerTile = 8;
348 }
349 }
350 else // normal double width
351 {
352 if (interlace)
353 {
354 DT = Renderers<DrawTile16, Interlace>::Functions;
355 DCT = Renderers<DrawClippedTile16, Interlace>::Functions;
356 DMP = Renderers<DrawMosaicPixel16, Interlace>::Functions;
357 DB = Renderers<DrawBackdrop16, Normal2x1>::Functions;
358 DM7BG1 = M7M1 ? Renderers<DrawMode7MosaicBG1, Normal2x1>::Functions : Renderers<DrawMode7BG1, Normal2x1>::Functions;
359 DM7BG2 = M7M2 ? Renderers<DrawMode7MosaicBG2, Normal2x1>::Functions : Renderers<DrawMode7BG2, Normal2x1>::Functions;
360 GFX.LinesPerTile = 4;
361 }
362 else
363 {
364 DT = Renderers<DrawTile16, Normal2x1>::Functions;
365 DCT = Renderers<DrawClippedTile16, Normal2x1>::Functions;
366 DMP = Renderers<DrawMosaicPixel16, Normal2x1>::Functions;
367 DB = Renderers<DrawBackdrop16, Normal2x1>::Functions;
368 DM7BG1 = M7M1 ? Renderers<DrawMode7MosaicBG1, Normal2x1>::Functions : Renderers<DrawMode7BG1, Normal2x1>::Functions;
369 DM7BG2 = M7M2 ? Renderers<DrawMode7MosaicBG2, Normal2x1>::Functions : Renderers<DrawMode7BG2, Normal2x1>::Functions;
370 GFX.LinesPerTile = 8;
371 }
372 }
373
374 GFX.DrawTileNomath = DT[0];
375 GFX.DrawClippedTileNomath = DCT[0];
376 GFX.DrawMosaicPixelNomath = DMP[0];
377 GFX.DrawBackdropNomath = DB[0];
378 GFX.DrawMode7BG1Nomath = DM7BG1[0];
379 GFX.DrawMode7BG2Nomath = DM7BG2[0];
380
381 int i;
382
383 if (!Settings.Transparency)
384 i = 0;
385 else
386 {
387 i = (Memory.FillRAM[0x2131] & 0x80) ? 4 : 1;
388 if (Memory.FillRAM[0x2131] & 0x40)
389 {
390 i++;
391 if (Memory.FillRAM[0x2130] & 2)
392 i++;
393 }
394 if (IPPU.MaxBrightness != 0xf)
395 {
396 if (i == 1)
397 i = 7;
398 else if (i == 3)
399 i = 8;
400 }
401
402 }
403
404 GFX.DrawTileMath = DT[i];
405 GFX.DrawClippedTileMath = DCT[i];
406 GFX.DrawMosaicPixelMath = DMP[i];
407 GFX.DrawBackdropMath = DB[i];
408 GFX.DrawMode7BG1Math = DM7BG1[i];
409 GFX.DrawMode7BG2Math = DM7BG2[i];
410}
411
412void S9xSelectTileConverter (int depth, bool8 hires, bool8 sub, bool8 mosaic)
413{
414 switch (depth)
415 {
416 case 8:
417 BG.ConvertTile = BG.ConvertTileFlip = ConvertTile8;
418 BG.Buffer = BG.BufferFlip = IPPU.TileCache[TILE_8BIT];
419 BG.Buffered = BG.BufferedFlip = IPPU.TileCached[TILE_8BIT];
420 BG.TileShift = 6;
421 BG.PaletteShift = 0;
422 BG.PaletteMask = 0;
423 BG.DirectColourMode = Memory.FillRAM[0x2130] & 1;
424
425 break;
426
427 case 4:
428 if (hires)
429 {
430 if (sub || mosaic)
431 {
432 BG.ConvertTile = ConvertTile4h_even;
433 BG.Buffer = IPPU.TileCache[TILE_4BIT_EVEN];
434 BG.Buffered = IPPU.TileCached[TILE_4BIT_EVEN];
435 BG.ConvertTileFlip = ConvertTile4h_odd;
436 BG.BufferFlip = IPPU.TileCache[TILE_4BIT_ODD];
437 BG.BufferedFlip = IPPU.TileCached[TILE_4BIT_ODD];
438 }
439 else
440 {
441 BG.ConvertTile = ConvertTile4h_odd;
442 BG.Buffer = IPPU.TileCache[TILE_4BIT_ODD];
443 BG.Buffered = IPPU.TileCached[TILE_4BIT_ODD];
444 BG.ConvertTileFlip = ConvertTile4h_even;
445 BG.BufferFlip = IPPU.TileCache[TILE_4BIT_EVEN];
446 BG.BufferedFlip = IPPU.TileCached[TILE_4BIT_EVEN];
447 }
448 }
449 else
450 {
451 BG.ConvertTile = BG.ConvertTileFlip = ConvertTile4;
452 BG.Buffer = BG.BufferFlip = IPPU.TileCache[TILE_4BIT];
453 BG.Buffered = BG.BufferedFlip = IPPU.TileCached[TILE_4BIT];
454 }
455
456 BG.TileShift = 5;
457 BG.PaletteShift = 10 - 4;
458 BG.PaletteMask = 7 << 4;
459 BG.DirectColourMode = FALSE;
460
461 break;
462
463 case 2:
464 if (hires)
465 {
466 if (sub || mosaic)
467 {
468 BG.ConvertTile = ConvertTile2h_even;
469 BG.Buffer = IPPU.TileCache[TILE_2BIT_EVEN];
470 BG.Buffered = IPPU.TileCached[TILE_2BIT_EVEN];
471 BG.ConvertTileFlip = ConvertTile2h_odd;
472 BG.BufferFlip = IPPU.TileCache[TILE_2BIT_ODD];
473 BG.BufferedFlip = IPPU.TileCached[TILE_2BIT_ODD];
474 }
475 else
476 {
477 BG.ConvertTile = ConvertTile2h_odd;
478 BG.Buffer = IPPU.TileCache[TILE_2BIT_ODD];
479 BG.Buffered = IPPU.TileCached[TILE_2BIT_ODD];
480 BG.ConvertTileFlip = ConvertTile2h_even;
481 BG.BufferFlip = IPPU.TileCache[TILE_2BIT_EVEN];
482 BG.BufferedFlip = IPPU.TileCached[TILE_2BIT_EVEN];
483 }
484 }
485 else
486 {
487 BG.ConvertTile = BG.ConvertTileFlip = ConvertTile2;
488 BG.Buffer = BG.BufferFlip = IPPU.TileCache[TILE_2BIT];
489 BG.Buffered = BG.BufferedFlip = IPPU.TileCached[TILE_2BIT];
490 }
491
492 BG.TileShift = 4;
493 BG.PaletteShift = 10 - 2;
494 BG.PaletteMask = 7 << 2;
495 BG.DirectColourMode = FALSE;
496
497 break;
498 }
499}
500