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