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 
ConvertTile2(uint8 * pCache,uint32 TileAddr,uint32)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 
ConvertTile4(uint8 * pCache,uint32 TileAddr,uint32)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 
ConvertTile8(uint8 * pCache,uint32 TileAddr,uint32)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 
ConvertTile2h_odd(uint8 * pCache,uint32 TileAddr,uint32 Tile)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 
ConvertTile4h_odd(uint8 * pCache,uint32 TileAddr,uint32 Tile)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 
ConvertTile2h_even(uint8 * pCache,uint32 TileAddr,uint32 Tile)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 
ConvertTile4h_even(uint8 * pCache,uint32 TileAddr,uint32 Tile)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 
S9xInitTileRenderer(void)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 
S9xSelectTileRenderers(int BGMode,bool8 sub,bool8 obj)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 
S9xSelectTileConverter(int depth,bool8 hires,bool8 sub,bool8 mosaic)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