all repos — mgba @ 2d7b1099a92a585dbe51026f2df36de00d7144df

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