all repos — mgba @ 11ccbca4ffd33e82e5595ce0f959d4d17a6d0cb9

mGBA Game Boy Advance Emulator

src/gba/renderers/software-mode0.c (view raw)

  1/* Copyright (c) 2013-2015 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "gba/renderers/software-private.h"
  7
  8#include <mgba/internal/gba/gba.h>
  9
 10#define BACKGROUND_TEXT_SELECT_CHARACTER \
 11	xBase = localX & 0xF8; \
 12	if (background->size & 1) { \
 13		xBase += (localX & 0x100) << 5; \
 14	} \
 15	screenBase = yBase + (xBase >> 3); \
 16	LOAD_16(mapData, screenBase << 1, vram); \
 17
 18#define DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_16(BLEND, OBJWIN) \
 19	paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
 20	palette = &mainPalette[paletteData]; \
 21	charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
 22	LOAD_32(tileData, charBase, vram); \
 23	if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
 24		tileData >>= 4 * mod8; \
 25		for (; outX < end; ++outX, ++pixel) { \
 26			BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
 27		} \
 28	} else { \
 29		for (outX = end - 1; outX >= renderer->start; --outX) { \
 30			uint32_t* pixel = &renderer->row[outX]; \
 31			BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
 32		} \
 33	}
 34
 35#define DRAW_BACKGROUND_MODE_0_TILE_PREFIX_16(BLEND, OBJWIN) \
 36	charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
 37	LOAD_32(tileData, charBase, vram); \
 38	paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
 39	palette = &mainPalette[paletteData]; \
 40	pixel = &renderer->row[outX]; \
 41	if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
 42		if (outX < renderer->start) { \
 43			tileData >>= 4 * (renderer->start - outX); \
 44			outX = renderer->start; \
 45			pixel = &renderer->row[outX]; \
 46		} \
 47		for (; outX < renderer->end; ++outX, ++pixel) { \
 48			BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
 49		} \
 50	} else { \
 51		tileData >>= 4 * (0x8 - mod8); \
 52		int end = renderer->end - 8; \
 53		if (end < -1) { \
 54			end = -1; \
 55		} \
 56		outX = renderer->end - 1; \
 57		pixel = &renderer->row[outX]; \
 58		for (; outX > end; --outX, --pixel) { \
 59			BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
 60		} \
 61		/* Needed for consistency checks */ \
 62		if (VIDEO_CHECKS) { \
 63			outX = renderer->end; \
 64			pixel = &renderer->row[outX]; \
 65		} \
 66	}
 67
 68#define DRAW_BACKGROUND_MODE_0_MOSAIC_16(BLEND, OBJWIN) \
 69	x = inX & 7; \
 70	if (mosaicWait) { \
 71		int baseX = x - (mosaicH - mosaicWait); \
 72		if (baseX < 0) { \
 73			int disturbX = (16 + baseX) >> 3; \
 74			inX -= disturbX << 3; \
 75			localX = tileX * 8 + inX; \
 76			BACKGROUND_TEXT_SELECT_CHARACTER; \
 77			localY = inY & 0x7; \
 78			if (GBA_TEXT_MAP_VFLIP(mapData)) { \
 79				localY = 7 - localY; \
 80			} \
 81			baseX -= disturbX << 3; \
 82			inX += disturbX << 3; \
 83		} else { \
 84			localX = tileX * 8 + inX; \
 85			BACKGROUND_TEXT_SELECT_CHARACTER; \
 86			localY = inY & 0x7; \
 87			if (GBA_TEXT_MAP_VFLIP(mapData)) { \
 88				localY = 7 - localY; \
 89			} \
 90		} \
 91		charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
 92		if (UNLIKELY(charBase >= 0x10000)) { \
 93			carryData = 0; \
 94		} else { \
 95			paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
 96			palette = &mainPalette[paletteData]; \
 97			LOAD_32(tileData, charBase, vram); \
 98			if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
 99				tileData >>= 4 * baseX; \
100			} else { \
101				tileData >>= 4 * (7 - baseX); \
102			} \
103			tileData &= 0xF; \
104			tileData |= tileData << 4; \
105			tileData |= tileData << 8; \
106			tileData |= tileData << 16; \
107			carryData = tileData; \
108		} \
109	} \
110	localX = tileX * 8 + inX; \
111	for (; length; ++tileX) { \
112		mapData = background->mapCache[(localX >> 3) & 0x3F]; \
113		localX += 8; \
114		localY = inY & 0x7; \
115		if (GBA_TEXT_MAP_VFLIP(mapData)) { \
116			localY = 7 - localY; \
117		} \
118		charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
119		tileData = carryData; \
120		for (; x < 8 && length; ++x, --length) { \
121			if (!mosaicWait) { \
122				if (UNLIKELY(charBase >= 0x10000)) { \
123					carryData = 0; \
124				} else { \
125					paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
126					palette = &mainPalette[paletteData]; \
127					LOAD_32(tileData, charBase, vram); \
128					if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
129						tileData >>= x * 4; \
130					} else { \
131						tileData >>= (7 - x) * 4; \
132					} \
133					tileData &= 0xF; \
134					tileData |= tileData << 4; \
135					tileData |= tileData << 8; \
136					tileData |= tileData << 16; \
137					carryData = tileData; \
138				} \
139				mosaicWait = mosaicH; \
140			} \
141			--mosaicWait; \
142			BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
143			++pixel; \
144		} \
145		x = 0; \
146	}
147
148#define DRAW_BACKGROUND_MODE_0_TILES_16(BLEND, OBJWIN) \
149	for (; tileX < tileEnd; ++tileX) { \
150		mapData = background->mapCache[(localX >> 3) & 0x3F]; \
151		localX += 8; \
152		localY = inY & 0x7; \
153		if (GBA_TEXT_MAP_VFLIP(mapData)) { \
154			localY = 7 - localY; \
155		} \
156		paletteData = GBA_TEXT_MAP_PALETTE(mapData) << 4; \
157		palette = &mainPalette[paletteData]; \
158		charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 5)) + (localY << 2); \
159		if (UNLIKELY(charBase >= 0x10000)) { \
160			pixel += 8; \
161			continue; \
162		} \
163		LOAD_32(tileData, charBase, vram); \
164		if (tileData) { \
165			if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
166				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
167				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 1); \
168				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 2); \
169				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 3); \
170				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 4); \
171				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 5); \
172				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 6); \
173				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 7); \
174			} else { \
175				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 7); \
176				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 6); \
177				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 5); \
178				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 4); \
179				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 3); \
180				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 2); \
181				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 1); \
182				BACKGROUND_DRAW_PIXEL_16(BLEND, OBJWIN, 0); \
183			} \
184		} \
185		pixel += 8; \
186	}
187
188#define DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_256(BLEND, OBJWIN) \
189	charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
190	int end2 = end - 4; \
191	if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
192		int shift = inX & 0x3; \
193		if (LIKELY(charBase < 0x10000)) { \
194			if (end2 > outX) { \
195				LOAD_32(tileData, charBase, vram); \
196				tileData >>= 8 * shift; \
197				shift = 0; \
198				for (; outX < end2; ++outX, ++pixel) { \
199					BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
200				} \
201			} \
202		} \
203		\
204		if (LIKELY(charBase < 0x10000)) { \
205			LOAD_32(tileData, charBase + 4, vram); \
206			tileData >>= 8 * shift; \
207			for (; outX < end; ++outX, ++pixel) { \
208				BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
209			} \
210		} \
211	} else { \
212		int start = outX; \
213		outX = end - 1; \
214		pixel = &renderer->row[outX]; \
215		if (LIKELY(charBase < 0x10000)) { \
216			if (end2 > start) { \
217				LOAD_32(tileData, charBase, vram); \
218				for (; outX >= end2; --outX, --pixel) { \
219					BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
220				} \
221				charBase += 4; \
222			} \
223		} \
224		\
225		if (LIKELY(charBase < 0x10000)) { \
226			LOAD_32(tileData, charBase, vram); \
227			for (; outX >= renderer->start; --outX, --pixel) { \
228				BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
229			} \
230		} \
231		outX = end; \
232		pixel = &renderer->row[outX]; \
233	}
234
235#define DRAW_BACKGROUND_MODE_0_TILE_PREFIX_256(BLEND, OBJWIN) \
236	charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
237	if (UNLIKELY(charBase >= 0x10000)) { \
238		return; \
239	} \
240	int end = mod8 - 4; \
241	pixel = &renderer->row[outX]; \
242	if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
243		if (end > 0) { \
244			LOAD_32(tileData, charBase, vram); \
245			for (; outX < renderer->end - end; ++outX, ++pixel) { \
246				BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
247			} \
248			charBase += 4; \
249		} \
250		\
251		LOAD_32(tileData, charBase, vram); \
252		for (; outX < renderer->end; ++outX, ++pixel) { \
253			BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
254		} \
255	} else { \
256		int shift = (8 - mod8) & 0x3; \
257		int start = outX; \
258		outX = renderer->end - 1; \
259		pixel = &renderer->row[outX]; \
260		if (end > 0) { \
261			LOAD_32(tileData, charBase, vram); \
262			tileData >>= 8 * shift; \
263			for (; outX >= start + 4; --outX, --pixel) { \
264				BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
265			} \
266			shift = 0; \
267		} \
268		\
269		LOAD_32(tileData, charBase + 4, vram); \
270		tileData >>= 8 * shift; \
271		for (; outX >= start; --outX, --pixel) { \
272			BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
273		} \
274		/* Needed for consistency checks */ \
275		if (VIDEO_CHECKS) { \
276			outX = renderer->end; \
277			pixel = &renderer->row[outX]; \
278		} \
279	}
280
281#define DRAW_BACKGROUND_MODE_0_TILES_256(BLEND, OBJWIN) \
282	for (; tileX < tileEnd; ++tileX) { \
283		mapData = background->mapCache[(localX >> 3) & 0x3F]; \
284		localX += 8; \
285		localY = inY & 0x7; \
286		if (GBA_TEXT_MAP_VFLIP(mapData)) { \
287			localY = 7 - localY; \
288		} \
289		charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
290		if (UNLIKELY(charBase >= 0x10000)) { \
291			pixel += 8; \
292			continue; \
293		} \
294		if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
295			LOAD_32(tileData, charBase, vram); \
296			if (tileData) { \
297					BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
298					BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
299					BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
300					BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
301			} \
302			pixel += 4; \
303			LOAD_32(tileData, charBase + 4, vram); \
304			if (tileData) { \
305					BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
306					BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
307					BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
308					BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
309			} \
310			pixel += 4; \
311		} else { \
312			LOAD_32(tileData, charBase + 4, vram); \
313			if (tileData) { \
314				BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
315				BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
316				BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
317				BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
318			} \
319			pixel += 4; \
320			LOAD_32(tileData, charBase, vram); \
321			if (tileData) { \
322				BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 3); \
323				BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 2); \
324				BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 1); \
325				BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
326			} \
327			pixel += 4; \
328		} \
329	}
330
331#define DRAW_BACKGROUND_MODE_0_MOSAIC_256(BLEND, OBJWIN) \
332	x = inX & 7; \
333	if (mosaicWait) { \
334		int baseX = x - (mosaicH - mosaicWait); \
335		if (baseX < 0) { \
336			int disturbX = (16 + baseX) >> 3; \
337			inX -= disturbX << 3; \
338			localX = tileX * 8 + inX; \
339			BACKGROUND_TEXT_SELECT_CHARACTER; \
340			localY = inY & 0x7; \
341			if (GBA_TEXT_MAP_VFLIP(mapData)) { \
342				localY = 7 - localY; \
343			} \
344			baseX -= disturbX << 3; \
345			inX += disturbX << 3; \
346		} else { \
347			localX = tileX * 8 + inX; \
348			BACKGROUND_TEXT_SELECT_CHARACTER; \
349			localY = inY & 0x7; \
350			if (GBA_TEXT_MAP_VFLIP(mapData)) { \
351				localY = 7 - localY; \
352			} \
353		} \
354		charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
355		if (UNLIKELY(charBase >= 0x10000)) { \
356			carryData = 0; \
357		} else { \
358			LOAD_32(tileData, charBase, vram); \
359			if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
360				if (x >= 4) { \
361					LOAD_32(tileData, charBase + 4, vram); \
362					tileData >>= (x - 4) * 8; \
363				} else { \
364					LOAD_32(tileData, charBase, vram); \
365					tileData >>= x * 8; \
366				} \
367			} else { \
368				if (x >= 4) { \
369					LOAD_32(tileData, charBase, vram); \
370					tileData >>= (7 - x) * 8; \
371				} else { \
372					LOAD_32(tileData, charBase + 4, vram); \
373					tileData >>= (3 - x) * 8; \
374				} \
375			} \
376			tileData &= 0xFF; \
377			carryData = tileData; \
378		} \
379	} \
380	localX = tileX * 8 + inX; \
381	for (; length; ++tileX) { \
382		mapData = background->mapCache[(localX >> 3) & 0x3F]; \
383		localX += 8; \
384		localY = inY & 0x7; \
385		if (GBA_TEXT_MAP_VFLIP(mapData)) { \
386			localY = 7 - localY; \
387		} \
388		charBase = (background->charBase + (GBA_TEXT_MAP_TILE(mapData) << 6)) + (localY << 3); \
389		tileData = carryData; \
390		for (x = 0; x < 8 && length; ++x, --length) { \
391			if (!mosaicWait) { \
392				if (UNLIKELY(charBase >= 0x10000)) { \
393					carryData = 0; \
394				} else { \
395					if (!GBA_TEXT_MAP_HFLIP(mapData)) { \
396						if (x >= 4) { \
397							LOAD_32(tileData, charBase + 4, vram); \
398							tileData >>= (x - 4) * 8; \
399						} else { \
400							LOAD_32(tileData, charBase, vram); \
401							tileData >>= x * 8; \
402						} \
403					} else { \
404						if (x >= 4) { \
405							LOAD_32(tileData, charBase, vram); \
406							tileData >>= (7 - x) * 8; \
407						} else { \
408							LOAD_32(tileData, charBase + 4, vram); \
409							tileData >>= (3 - x) * 8; \
410						} \
411					} \
412					tileData &= 0xFF; \
413					carryData = tileData; \
414				} \
415				mosaicWait = mosaicH; \
416			} \
417			tileData |= tileData << 8; \
418			--mosaicWait; \
419			BACKGROUND_DRAW_PIXEL_256(BLEND, OBJWIN, 0); \
420			++pixel; \
421		} \
422	}
423
424#define DRAW_BACKGROUND_MODE_0(BPP, BLEND, OBJWIN) \
425	uint32_t* pixel = &renderer->row[outX]; \
426	if (background->mosaic && GBAMosaicControlGetBgH(renderer->mosaic)) { \
427		int mosaicH = GBAMosaicControlGetBgH(renderer->mosaic) + 1; \
428		int x; \
429		int mosaicWait = (mosaicH - outX + GBA_VIDEO_HORIZONTAL_PIXELS * mosaicH) % mosaicH; \
430		int carryData = 0; \
431		paletteData = 0; /* Quiets compiler warning */ \
432		DRAW_BACKGROUND_MODE_0_MOSAIC_ ## BPP (BLEND, OBJWIN) \
433		return; \
434	} \
435	\
436	if (inX & 0x7) { \
437		localX = tileX * 8 + inX; \
438		BACKGROUND_TEXT_SELECT_CHARACTER; \
439		localY = inY & 0x7; \
440		if (GBA_TEXT_MAP_VFLIP(mapData)) { \
441			localY = 7 - localY; \
442		} \
443		int mod8 = inX & 0x7; \
444		int end = outX + 0x8 - mod8; \
445		if (end > renderer->end) { \
446			end = renderer->end; \
447		} \
448		if (UNLIKELY(end == outX)) { \
449			return; \
450		} \
451		if (UNLIKELY(end < outX)) { \
452			mLOG(GBA_VIDEO, FATAL, "Out of bounds background draw!"); \
453			return; \
454		} \
455		DRAW_BACKGROUND_MODE_0_TILE_SUFFIX_ ## BPP (BLEND, OBJWIN) \
456		outX = end; \
457		if (tileX < tileEnd) { \
458			++tileX; \
459		} else if (VIDEO_CHECKS && UNLIKELY(tileX > tileEnd)) { \
460			mLOG(GBA_VIDEO, FATAL, "Invariant doesn't hold in background draw! tileX (%u) > tileEnd (%u)", tileX, tileEnd); \
461			return; \
462		} \
463		length -= end - renderer->start; \
464	} \
465	/*! TODO: Make sure these lines can be removed */ \
466	/*!*/ pixel = &renderer->row[outX]; \
467	outX += (tileEnd - tileX) * 8; \
468	/*!*/ if (VIDEO_CHECKS &&  UNLIKELY(outX > GBA_VIDEO_HORIZONTAL_PIXELS)) { \
469	/*!*/	mLOG(GBA_VIDEO, FATAL, "Out of bounds background draw would occur!"); \
470	/*!*/	return; \
471	/*!*/ } \
472	localX = (tileX * 8 + inX) & 0x1FF; \
473	DRAW_BACKGROUND_MODE_0_TILES_ ## BPP (BLEND, OBJWIN) \
474	if (length & 0x7) { \
475		localX = tileX * 8 + inX; \
476		BACKGROUND_TEXT_SELECT_CHARACTER; \
477		localY = inY & 0x7; \
478		if (GBA_TEXT_MAP_VFLIP(mapData)) { \
479			localY = 7 - localY; \
480		} \
481		int mod8 = length & 0x7; \
482		if (VIDEO_CHECKS && UNLIKELY(outX + mod8 != renderer->end)) { \
483			mLOG(GBA_VIDEO, FATAL, "Invariant doesn't hold in background draw!"); \
484			return; \
485		} \
486		DRAW_BACKGROUND_MODE_0_TILE_PREFIX_ ## BPP (BLEND, OBJWIN) \
487	} \
488	if (VIDEO_CHECKS && UNLIKELY(&renderer->row[outX] != pixel)) { \
489		mLOG(GBA_VIDEO, FATAL, "Background draw ended in the wrong place! Diff: %" PRIXPTR, &renderer->row[outX] - pixel); \
490	} \
491	if (VIDEO_CHECKS && UNLIKELY(outX > GBA_VIDEO_HORIZONTAL_PIXELS)) { \
492		mLOG(GBA_VIDEO, FATAL, "Out of bounds background draw occurred!"); \
493		return; \
494	}
495
496void GBAVideoSoftwareRendererDrawBackgroundMode0(struct GBAVideoSoftwareRenderer* renderer, struct GBAVideoSoftwareBackground* background, int y) {
497	int inX = (renderer->start + background->x - background->offsetX) & 0x1FF;
498	int length = renderer->end - renderer->start;
499	if (background->mosaic) {
500		int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1;
501		y -= y % mosaicV;
502	}
503	int inY = y + background->y - background->offsetY;
504	uint16_t mapData;
505
506	unsigned yBase = inY & 0xF8;
507	if (background->size == 2) {
508		yBase += inY & 0x100;
509	} else if (background->size == 3) {
510		yBase += (inY & 0x100) << 1;
511	}
512	yBase = (background->screenBase >> 1) + (yBase << 2);
513
514	int localX;
515	int localY;
516
517	unsigned xBase;
518
519	uint32_t flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND;
520	flags |= FLAG_TARGET_2 * background->target2;
521	int objwinFlags = FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->objwin.packed));
522	objwinFlags |= flags;
523	flags |= FLAG_TARGET_1 * (background->target1 && renderer->blendEffect == BLEND_ALPHA && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed));
524	if (renderer->blendEffect == BLEND_ALPHA && renderer->blda == 0x10 && renderer->bldb == 0) {
525		flags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2);
526		objwinFlags &= ~(FLAG_TARGET_1 | FLAG_TARGET_2);
527	}
528
529	uint32_t screenBase;
530	uint32_t charBase;
531	int variant = background->target1 && GBAWindowControlIsBlendEnable(renderer->currentWindow.packed) && (renderer->blendEffect == BLEND_BRIGHTEN || renderer->blendEffect == BLEND_DARKEN);
532	color_t* mainPalette = renderer->normalPalette;
533	if (renderer->d.highlightAmount && background->highlight) {
534		mainPalette = renderer->highlightPalette;
535	}
536	if (variant) {
537		mainPalette = renderer->variantPalette;
538		if (renderer->d.highlightAmount && background->highlight) {
539			mainPalette = renderer->highlightVariantPalette;
540		}
541	}
542	color_t* palette = mainPalette;
543	PREPARE_OBJWIN;
544
545	int outX = renderer->start;
546
547	uint32_t tileData;
548	uint32_t current;
549	int pixelData;
550	int paletteData;
551	int tileX;
552	int tileEnd = ((length + inX) >> 3) - (inX >> 3);
553	uint16_t* vram = renderer->d.vram;
554
555	if (background->yCache != inY >> 3) {
556		localX = 0;
557		for (tileX = 0; tileX < 64; ++tileX, localX += 8) {
558			BACKGROUND_TEXT_SELECT_CHARACTER;
559			background->mapCache[tileX] = mapData;
560		}
561		background->yCache = inY >> 3;
562	}
563
564	tileX = 0;
565	if (!objwinSlowPath) {
566		if (!(flags & FLAG_TARGET_2)) {
567			if (!background->multipalette) {
568				DRAW_BACKGROUND_MODE_0(16, NoBlend, NO_OBJWIN);
569			} else {
570				DRAW_BACKGROUND_MODE_0(256, NoBlend, NO_OBJWIN);
571			}
572		} else {
573			if (!background->multipalette) {
574				DRAW_BACKGROUND_MODE_0(16, Blend, NO_OBJWIN);
575			} else {
576				DRAW_BACKGROUND_MODE_0(256, Blend, NO_OBJWIN);
577			}
578		}
579	} else {
580		if (!(flags & FLAG_TARGET_2)) {
581			if (!background->multipalette) {
582				DRAW_BACKGROUND_MODE_0(16, NoBlend, OBJWIN);
583			} else {
584				DRAW_BACKGROUND_MODE_0(256, NoBlend, OBJWIN);
585			}
586		} else {
587			if (!background->multipalette) {
588				DRAW_BACKGROUND_MODE_0(16, Blend, OBJWIN);
589			} else {
590				DRAW_BACKGROUND_MODE_0(256, Blend, OBJWIN);
591			}
592		}
593	}
594}