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 | |
9 | using namespace TileImpl; |
10 | |
11 | namespace { |
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 | |
240 | void 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 | |
301 | void 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 | |
412 | void 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 | |